Создание пользовательского шлюза 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вызов. Это содержимое, которое еще не появилось в приведенном выше примере.Прочитав последующий текст, вы сможете лучше понять процесс вызова.
Последняя статья "Учебник по переходу на ноль - сервисное подразделение и создание проекта"