The User API Gateway is created

CD to FoodGuides directory. Create an API folder

mkdir -p usermanage/api && cd usermanage/api
Copy the code

Create the user.api file

goctl api -o user.api
Copy the code

Defining API services

info(
	title: // UserApi
	desc: // User service related apis
)

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    // User login
	post /users/login(LoginRequest) returns(LoginResponse)
	
	@handler Register // User registration
	post /users/register(RegisterRequest) returns(RegisterResponse)
	
	@handler UserInfo // User information
	post /users/userinfo(UserinfoRequest) returns(UserinfoResponse)
}
Copy the code

We defined three user-apis: Login Register UserInfo

Generate the User-API service

goctl api go -api user.api -dir .
Copy the code

Check out the API directory

➜ API git tree. (master) ✗ ├ ─ ─ etc │ └ ─ ─ the user - API. Yaml ├ ─ ─ internal │ ├ ─ ─ the config │ │ └ ─ ─ the config.go│ ├─ Finger Exercises ─ Finger Exercises.go│ │ ├ ─ ─ registerhandler.go│ │ ├ ─ ─ routes.go│ │ └ ─ ─ userinfohandler.go│ ├─ Logic │ ├─ LoginLogic.go│ │ ├ ─ ─ registerlogic.go│ │ └ ─ ─ userinfologic.go│ ├── │ ├─ ├─ ├─go│ ├ ─ garbage ─ garbagego├ ─ ─ user. API └ ─ ─ the user.go
Copy the code

To start the service, note that before starting the service, you need to make sure that the ningxi-compose used in the previous article is up and running.

go run user.go -f etc/user-api.yaml
Copy the code

Understand how services run

The Goctl tool helps you create API services quickly and easily. But without an understanding of how API services work, it can be confusing to look at the project structure.

  • api/etcUnder theuser-api.yamlFile. The file is configuredapiVariables required by the service, such as the service nameName, interface addressHost, port number,PortInformation such as,MySQL,Redis,rpcAnd so the configuration is also written here.
  • apiUnder theuser.apiFile. The file definesapiThe interface information provided by the service and subsequent interface additions are also handled here. And then callgoctlRegenerate the service.
  • apiUnder theuser.goFile. The file isapiThe entry file for the service, where it all starts.

Internal folder

The internal implementation code for the API service is placed under this folder.

Go file in internal/config. You will notice that the definition of this file is similar to that of user-api.yaml. Yes. The user-api.yaml entry file in the user.go method is parsed into a Config object. So their values correspond one to one.

The file of phones. go under internal or handler is configured. This file is the routing file of the API service, which defines the request mode of each interface, the interface path, and the method triggered by the interface. For example: the client request the http://localhost:8888/users/register in the post way, the API service will trigger RegisterHandler () method.

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),
			},
		},
	)
}
Copy the code

Xxxhandler. go file under internal/handler. The implementation of each interface trigger method is written in this file.

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

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

You can see that the RegisterHandler first parses the received parameters. We then call logic.newregisterLogic () and see that RegisterHandler is not the final implementation. The final business processing is actually in the various logic.go files in the Logic folder.

The xxxlogic.go file is stored in internal/logic. We will eventually call the corresponding RPC service in each logic implementation.

The servicecontext.go file in internal/ SVC. This file holds the CONFIG object for the API service and instantiates the objects for each RPC service. The SVC object is then passed from Handle to the Logic method. Finally, Logic is implemented through SVC objects when calling RPC services.

func (l *LoginLogic) Login(req types.LoginRequest) (*types.LoginResponse, error) {
	
	resp,err := l.svcCtx.User.Login(l.ctx, &user.LoginRequest{  // The user RPC service is invoked via svcCtx
		Email: req.Email,
		Password: req.Password,
	});

}
Copy the code

The types.go file under internal/types. This file defines the various constructs we declared in the User.api template file.

Call procedure carding

The following uses the login interface as an example.

user.goImport file passyamlConfiguration file, instantiateconfigObject.

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

instantiationServiceContextobject

ctx := svc.NewServiceContext(c)
Copy the code

CTX holds the Config object internally. The User RPX service is initialized. CTX then has the ability to call RPC services.

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

instantiationServerObject.

server := rest.MustNewServer(c.RestConf)
Copy the code

Routing implementation, noticectxBe passed to thehandlersThe internal.

handler.RegisterHandlers(server, ctx)
Copy the code

apiService runs

server.Start()
Copy the code

When the client invokes the login interface. The LoginHandler method is triggered

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

LoginHandler then calls the LoginLogic method

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,
	});
	
}
Copy the code

In the Login. We invoked the Login method in the User RPC service via l.svcctx.

After processing the data, the interface responds layer by layer, and finally completes the invocation of the client interface.

Along the way, a call to RPC comes up. The above example has not yet appeared, you will read the text after the next, and then understand the call process, to be able to understand better.

Previous post go-Zero Tutorial: Service partitioning and Project Creation

The next go-Zero tutorial — User Rpc-Login