新建两个WebApi:
根据UserId获取UserInfo
获取所有的年龄大于30的UserInfo
期望如下:
请求http://xxxx:8080?userId=1
,返回如下格式:
{
user_id:1,
user_name:"tony",
age:35
}
http://xxxx:8081?age=30
返回格式如下:[
{
user_id:1,
user_name:"tony",
age:35
},
{
user_id:2,
user_name:"TEST",
age:40
},
]
为了避免命名冲突所以在三个文件夹和包名称前面加上了My
,不过不影响,只不过是名称而已
go mod init microservicetest
go get -u github.com/go-kit/kit
model.go
:
package Model
type UserInfo struct {
UserId int `json:"user_id"`
UserName string `json:"user_name"`
Age int `json:"age"`
}
业务逻辑
上的请求和响应业务逻辑上的请求和响应,需要为结构体
请注意,为什么要定义业务逻辑上的请求和响应:
这里有个区分:
这两个是不一样的,但是有一些关键的信息关联。
传输层(http请求)的参数,只是提供一些关键的简单的信息,比如用户ID等
业务逻辑处理的请求,包含业务逻辑处理所需要的全部参数。
比如:http请求中包含很多参数,有用户ID,有token,有用户姓名,我们的逻辑处理可能只需要用到用户ID。
又比如:http请求中只包含关键信息用户ID,但是连接数据的信息没有包含,业务逻辑层的处理函数可能会使用到这些。
简单来讲,就是如下的一个转换过程:
从http
请求中得到我们需要的信息,组成业务逻辑的request
。
这个定义过程,放在endpoint.go
中:
http://xxxx:8080?userId=1
,返回如下格式:{
user_id:1,
user_name:"tony",
age:35
}
对应的Request与Response如下:
type GetUserInfoByUserIdRequest struct{
UserId int `json:"user_id"`
}
type GetUserInfoByUserIdResponse struct{
UserInfo
}
http://xxxx:8081?age=30
返回格式如下:[
{
user_id:1,
user_name:"tony",
age:35
},
{
user_id:2,
user_name:"TEST",
age:40
},
]
对应的Request与Response如下:
type GetUserInfoByMoreThanAgeRequest struct{
Age int `json:"age"`
}
type GetUserInfoByMoreThanAgeResponse struct{
UserInfos []UserInfo
}
在MyServer
中定义核心业务逻辑。即如何根据业务逻辑的参数得到业务逻辑的返回值。
这里可能需要连接数据,可能需要从其他地方请求数据等等。
server.go
:
package Myserver
import (
"microservicetest/Model"
)
type IMyServer interface {
GetUserById(userId int) Model.UserInfo
GetUsersByMoreThanAge(age int) []Model.UserInfo
}
type Myserver struct {
}
func (s *Myserver) GetUserById(userId int) Model.UserInfo {
return Model.UserInfo{
UserId: 1,
UserName: "tony",
Age: 35,
}
}
func (s *Myserver) GetUsersByMoreThanAge(age int) []Model.UserInfo {
return []Model.UserInfo{
Model.UserInfo{
UserId: 1,
UserName: "tony",
Age: 35,
},
Model.UserInfo{
UserId: 2,
UserName: "TEST",
Age: 40,
},
}
}
Myendpoint
中,调用Myserver
中的业务逻辑,构造Endpointendpoint.go
:
func MakeGetUserInfoByUserIdEndpoint(s Myserver.IMyServer) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
r, ok := request.(GetUserInfoByUserIdRequest)
if !ok {
return GetUserInfoByUserIdResponse{}, nil
}
return GetUserInfoByUserIdResponse{UserInfo: s.GetUserById(r.UserId)}, nil
}
}
func MakeGetUserInfoByMoreThanAgeEndpoint(s Myserver.IMyServer) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
r, ok := request.(GetUserInfoByMoreThanAgeRequest)
if !ok {
return GetUserInfoByMoreThanAgeResponse{}, nil
}
return GetUserInfoByMoreThanAgeResponse{UserInfos: s.GetUsersByMoreThanAge(r.Age)}, nil
}
}
Transport层定义了如何从*http.Request
中解析到我们需要的参数,以及通过http.ResponseWriter
将最终的结果以什么样的格式和形式反馈出去.
transport.go
:
package Mytransport
import (
"context"
"encoding/json"
"microservicetest/Myendpoint"
"net/http"
"strconv"
)
func DecodeGetUserByIdRequest(c context.Context, request *http.Request) (interface{}, error) {
userIdStr := request.URL.Query().Get("user_id")
userId, err := strconv.Atoi(userIdStr)
if err != nil {
return nil, err
}
return Myendpoint.GetUserInfoByUserIdRequest{UserId: userId}, nil
}
func EncodeResponse(c context.Context, w http.ResponseWriter, response interface{}) error {
return json.NewEncoder(w).Encode(response)
}
func DecodeGetUserByMoreThanAgeRequest(c context.Context, request *http.Request) (interface{}, error) {
ageStr := request.URL.Query().Get("age")
age, err := strconv.Atoi(ageStr)
if err != nil {
return nil, err
}
return Myendpoint.GetUserInfoByMoreThanAgeRequest{Age: age}, nil
}
main.go
:
package main
import (
"fmt"
"microservicetest/Myendpoint"
"microservicetest/Myserver"
"microservicetest/Mytransport"
"net/http"
kitHttp "github.com/go-kit/kit/transport/http"
)
func main() {
s := &Myserver.Myserver{}
getUserInfoByUserIdServer := Myendpoint.MakeGetUserInfoByUserIdEndpoint(s)
getUserInfoByMoreThanAgeServer := Myendpoint.MakeGetUserInfoByMoreThanAgeEndpoint(s)
s1 := kitHttp.NewServer(getUserInfoByUserIdServer, Mytransport.DecodeGetUserByIdRequest, Mytransport.EncodeResponse)
s2 := kitHttp.NewServer(getUserInfoByMoreThanAgeServer, Mytransport.DecodeGetUserByMoreThanAgeRequest, Mytransport.EncodeResponse)
go http.ListenAndServe(":8080", s1)
go http.ListenAndServe(":8081", s2)
fmt.Println("server is start")
select {}
}