Учебное пособие по переходу на ноль — User API Gateway

Go

Создание пользовательского шлюза API

cdприбытьFoodGuidesПод содержанием. Создайтеapiпапка

mkdir -p usermanage/api && cd usermanage/api

Создайтеuser.apiдокумент

goctl api -o user.api

определениеapiСлужить

info(
	title: // UserApi
	desc: // 用户服务相关API
)

type LoginRequest struct {
	Email 	 	string `json:"email"`
	Password 	string `json:"password"`
}

type LoginResponse struct {
	UserReply
}

type RegisterRequest struct {
	Username    string `json:"username"`
	Email 	    string `json:"email"`
	Password    string `json:"password"`
}

type RegisterResponse struct {
	UserReply
}

type UserinfoRequest struct {
	Userid 		string `json:"userid"`
	Token 		string `json:"token"`
}

type UserinfoResponse struct {
	UserReply
}

type UserReply {
	Id		 	int64 `json:"id"`
	Username 	string `json:"username"`
	Email 		string `json:"email"`
	JwtToken
}

type JwtToken {
	AccessToken  string `json:"accessToken,omitempty"`
	AccessExpire int64 `json:"accessExpire,omitempty"`
	RefreshAfter int64 `json:"refreshAfter,omitempty"`
}

service user-api {
	@handler Login    // 用户登录
	post /users/login(LoginRequest) returns(LoginResponse)
	
	@handler Register // 用户注册
	post /users/register(RegisterRequest) returns(RegisterResponse)
	
	@handler UserInfo // 用户信息
	post /users/userinfo(UserinfoRequest) returns(UserinfoResponse)
}

Мы определяем триuser-api:Login Register UserInfo

генерироватьuser-apiСлужить

goctl api go -api user.api -dir .

Проверьте этоapiсодержание

➜  api git:(master) ✗ tree
.
├── etc
│   └── user-api.yaml
├── internal
│   ├── config
│   │   └── config.go
│   ├── handler
│   │   ├── loginhandler.go
│   │   ├── registerhandler.go
│   │   ├── routes.go
│   │   └── userinfohandler.go
│   ├── logic
│   │   ├── loginlogic.go
│   │   ├── registerlogic.go
│   │   └── userinfologic.go
│   ├── svc
│   │   └── servicecontext.go
│   └── types
│       └── types.go
├── user.api
└── user.go

Запускаем службу, обратите внимание, что при запуске службы нужно убедиться, что та, что использовалась в предыдущей статьеningxi-composeбеги нормально.

go run user.go -f etc/user-api.yaml

Понять, как работает сервис

goctlИнструменты могут легко и быстро помочь нам создатьapiСлужить. Но если вы не можете понятьapiКак работает сервис, глядя на структуру проекта будет очень запутанно.

  • api/etcвнизuser-api.yamlдокумент. Этот файл настраиваетapiНекоторые переменные, требуемые службой, например имя службы.Name,адрес интерфейсаHost,Номер портаPortи другая информация,MySQL,Redis,rpcДругие конфигурации также написаны здесь.
  • apiвнизuser.apiдокумент. Этот файл определяетapiИнформация об интерфейсе, предоставляемая службой, и последующие добавления интерфейса также обрабатываются здесь. тогда позвониgoctlВосстановите службу.
  • apiвнизuser.goдокумент. ФайлapiВходной файл для службы, здесь все начинается.

внутренняя папка

apiВнутренний код реализации сервиса находится в этой папке.

internal/configвнизconfig.goдокумент. Вы обнаружите, что файл определяет иuser-api.yamlопределение аналогичное. да.user-api.yamlсуществуетuser.goВходной файл находится вmainметод, он анализируется какconfigобъект. Так что их значения взаимно однозначно соответствуют.

internal/handlerвнизrouters.goдокумент. ФайлapiФайл маршрутизации службы определяет метод запроса каждого интерфейса, путь к интерфейсу и метод, запускаемый интерфейсом. Например: клиент начинается сpostзапрошенный способhttp://localhost:8888/users/register,ноapiслужба сработаетRegisterHandler() метод.

func RegisterHandlers(engine *rest.Server, serverCtx *svc.ServiceContext) {
	engine.AddRoutes(
		[]rest.Route{
			{
				Method:  http.MethodPost,
				Path:    "/users/login",
				Handler: LoginHandler(serverCtx),
			},
			{
				Method:  http.MethodPost,
				Path:    "/users/register",
				Handler: RegisterHandler(serverCtx),
			},
			{
				Method:  http.MethodPost,
				Path:    "/users/userinfo",
				Handler: UserInfoHandler(serverCtx),
			},
		},
	)
}

internal/handlerвнизxxxhandler.goдокумент. В этом файле записывается конкретная реализация каждого метода триггера интерфейса.

func RegisterHandler(ctx *svc.ServiceContext) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var req types.RegisterRequest
		if err := httpx.Parse(r, &req); err != nil {
			httpx.Error(w, err)
			return
		}

		l := logic.NewRegisterLogic(r.Context(), ctx)
		resp, err := l.Register(req)
		if err != nil {
			httpx.Error(w, err)
		} else {
			httpx.OkJson(w, resp)
		}
	}
}

можно увидетьRegisterHandlerСначала анализируются полученные параметры. а потом позвонилlogic.NewRegisterLogic(), его можно найтиRegisterHandlerЭто не окончательная реализация, окончательная обработка бизнеса фактически находится в стадии разработки.logicпод каждой папкойlogic.goв файле.

internal/logicвнизxxxlogic.goдокумент. мы в конце концовlogicв методе реализации вызвать соответствующийrpcСлужить.

internal/svcвнизservicecontext.goдокумент. Файл сохраненapiУслугиconfigобъект и создать экземпляр каждогоrpcОбъект услуги. потомsvcобъект будет изhandleперейти кlogicметод. В конце концовlogicвызовrpcтакже через сервисsvcобъект для достижения.

func (l *LoginLogic) Login(req types.LoginRequest) (*types.LoginResponse, error) {
	
	resp,err := l.svcCtx.User.Login(l.ctx, &user.LoginRequest{  // 通过svcCtx 来调用了user rpc服务
		Email: req.Email,
		Password: req.Password,
	});

}

internal/typesвнизtypes.goдокумент. Этот файл определяет нашуuser.apiКаждая структура объявлена ​​в файле шаблона.

Подведение итогов процесса вызова

позвонить как клиентloginВозьмем для примера интерфейс.

user.goвходной файл черезyamlконфигурационный файл, экземплярconfigобъект.

var configFile = flag.String("f", "etc/user-api.yaml", "the config file")
func main() {
	flag.Parse()
	var c config.Config
	conf.MustLoad(*configFile, &c)
	}

создавать экземплярServiceContextобъект

ctx := svc.NewServiceContext(c)

ctxхранится внутриconfigобъект. и инициализированuser rpxСлужить. тогдаctxпозвониrpcумение служить.

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config: c,
		User: userclient.NewUser(zrpc.MustNewClient(c.User)),
	}
}

создавать экземплярServerобъект.

server := rest.MustNewServer(c.RestConf)

Реализация маршрутизации, примечаниеctxпередаетсяhandlersНаизнанку.

handler.RegisterHandlers(server, ctx)

apiслужба работает

server.Start()

когда клиент звонитloginинтерфейс. вызыватьLoginHandlerметод

func LoginHandler(ctx *svc.ServiceContext) http.HandlerFunc {
		
		l := logic.NewLoginLogic(r.Context(), ctx)
		resp, err := l.Login(req)
		
}

потомLoginHandlerперечислитьLoginLogicметод

func (l *LoginLogic) Login(req types.LoginRequest) (*types.LoginResponse, error) {

	resp,err := l.svcCtx.User.Login(l.ctx, &user.LoginRequest{
		Email: req.Email,
		Password: req.Password,
	});
	
}

существуетLoginвнутри. мы проходим l.svcCtx.называетсяUser rpcв сервисеLoginметод.

После обработки данных интерфейс отвечает слой за слоем и, наконец, завершает вызов клиентского интерфейса.

В процессе осмысленияrpcвызов. Это содержимое, которое еще не появилось в приведенном выше примере.Прочитав последующий текст, вы сможете лучше понять процесс вызова.

Последняя статья "Учебник по переходу на ноль - сервисное подразделение и создание проекта"

Следующая статья "go-zero tutorial - User rpc - Login"