抖音项目实现2: api层的实现 | 青训营笔记

148 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天

目录导航:
1. 测试user微服务
2. api层的实现
3. github仓库地址

1.测试user微服务

接上一篇实现了user微服务,并将服务注册到了etcd上。测试为服务业编写一个客户端发现服务并进行rpc调用,新建douyin/test/userRpc.go如下:

package main

import (
   "context"
   "douyin/kitex_gen/user"
   "douyin/kitex_gen/user/userservice"
   "douyin/pkg/constants"
   "douyin/pkg/middleware"
   "github.com/cloudwego/kitex/client"
   "github.com/cloudwego/kitex/pkg/retry"
   etcd "github.com/kitex-contrib/registry-etcd"
   trace "github.com/kitex-contrib/tracer-opentracing"
   "log"
   "time"
)

func main() {
   r, err := etcd.NewEtcdResolver([]string{constants.EtcdAddress})
   if err != nil {
      panic(err)
   }

   c, err := userservice.NewClient(
      constants.UserServiceName,
      client.WithMiddleware(middleware.CommonMiddleware),
      client.WithInstanceMW(middleware.ClientMiddleware),
      client.WithMuxConnection(1),                       // mux
      client.WithRPCTimeout(3*time.Second),              // rpc timeout
      client.WithConnectTimeout(50*time.Millisecond),    // conn timeout
      client.WithFailureRetry(retry.NewFailurePolicy()), // retry
      client.WithSuite(trace.NewDefaultClientSuite()),   // tracer
      client.WithResolver(r),                            // resolver
   )
   if err != nil {
      panic(err)
   }

   req := &user.DouyinUserRegisterRequest{Username: "111111", Password: "124"}
   resp, err := c.CreateUser(context.Background(), req)

   req1 := &user.DouyinUserLoginRequest{Username: "111111", Password: "124"}
   resp1, err := c.CheckUser(context.Background(), req1)

   req2 := &user.DouyinUserRequest{UserId: 1, Token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjIyOTg3NjkyMjMsImlhdCI6MTY3NjY4OTIyMywiaXNzIjoiZG91eWluIn0.Yot75U-ZZlXwUfaXEEag6A2Vf-U4LL-wO3RKb07KQlA"} //token是复制的注册后返回的token
   resp2, err := c.QueryCurUser(context.Background(), req2)

   if err != nil {
      log.Fatal(err)
   }
   log.Println(resp)
   log.Println(resp1)
   log.Println(resp2)
   time.Sleep(time.Second)
}

开启user微服务:终端进入/douyin/cmd/user输入以下指令:

bash ./build.sh
 bash ./output/bootstrap.sh

提示如下即成功开启微服务: sendpix1.jpg 编译运行userRpc.go,输出以下结果就是成功进行了服务发现并且完成user rpc调用: sendpix3.jpg

2.api层的实现

服务发现&rpc调用

新建douyin/cmd/api/rpc文件夹,文件存放初始化rpc调用的init.go文件以及对外提供rpc调用接口的user.go文件代码如下:

package rpc

import (
   "context"
   "douyin/kitex_gen/user"
   "douyin/kitex_gen/user/userservice"
   "douyin/pkg/constants"
   "douyin/pkg/errno"
   "douyin/pkg/middleware"
   trace "github.com/kitex-contrib/tracer-opentracing"
   "time"

   "github.com/cloudwego/kitex/client"
   "github.com/cloudwego/kitex/pkg/retry"
   etcd "github.com/kitex-contrib/registry-etcd"
)

var userClient userservice.Client

func initUserRpc() {
   r, err := etcd.NewEtcdResolver([]string{constants.EtcdAddress})
   if err != nil {
      panic(err)
   }

   c, err := userservice.NewClient(
      constants.UserServiceName,
      client.WithMiddleware(middleware.CommonMiddleware),
      client.WithInstanceMW(middleware.ClientMiddleware),
      client.WithMuxConnection(1),                       // mux
      client.WithRPCTimeout(3*time.Second),              // rpc timeout
      client.WithConnectTimeout(50*time.Millisecond),    // conn timeout
      client.WithFailureRetry(retry.NewFailurePolicy()), // retry
      client.WithSuite(trace.NewDefaultClientSuite()),   // tracer
      client.WithResolver(r),                            // resolver
   )
   if err != nil {
      panic(err)
   }
   userClient = c
}

// CreateUser create user info
func CreateUser(ctx context.Context, req *user.DouyinUserRegisterRequest) (int64, string, error) {
   resp, err := userClient.CreateUser(ctx, req)
   if err != nil {
      return -1, "", err
   }
   if resp.BaseResp.StatusCode != 0 {
      return -1, "", errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
   }
   return resp.UserId, resp.Token, nil
}

// CheckUser check user info
func CheckUser(ctx context.Context, req *user.DouyinUserLoginRequest) (int64, string, error) {
   resp, err := userClient.CheckUser(ctx, req)
   if err != nil {
      return -1, "", err
   }
   if resp.BaseResp.StatusCode != 0 {
      return -1, "", errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
   }
   return resp.UserId, resp.Token, nil
}

// UserInfo user info format
type UserInfo struct {
   ID   int64  `json:"id"`
   Name string `json:"name"`
}

// QuryUser check user info
func QueryUser(ctx context.Context, req *user.DouyinUserRequest) (*UserInfo, error) {
   resp, err := userClient.QueryCurUser(ctx, req)
   if err != nil {
      return nil, err
   }
   if resp.BaseResp.StatusCode != 0 {
      return nil, errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
   }

   var userInfo UserInfo
   userInfo.ID = resp.User.Id
   userInfo.Name = resp.User.Name
   return &userInfo, nil
}

gin接收参数返回结果

新建douyin/cmd/api/handles文件夹,文件存放接收参数完成rpc调用返回结果的对应功能文件,user服务包括登录login.go,注册register.go,查询用户信息get_cur_user.go,这里举例register.go,其余代码详见文章末尾github仓库。

package handlers

import (
   "context"
   "douyin/cmd/api/rpc"
   "douyin/kitex_gen/user"
   "douyin/pkg/errno"
   "github.com/gin-gonic/gin"
   "log"
)

func Register(c *gin.Context) {
   var registerVar UserParam

   if err := c.BindQuery(&registerVar); err != nil {
      SendUserResponse(c, errno.ConvertErr(err), -1, "")
      return
   }
   log.Print(registerVar)

   if len(registerVar.Username) == 0 || len(registerVar.Password) == 0 {
      SendUserResponse(c, errno.ParamErr, -1, "")
      return
   }

   userID, token, err := rpc.CreateUser(context.Background(), &user.DouyinUserRegisterRequest{
      Username: registerVar.Username,
      Password: registerVar.Password,
   })

   if err != nil {
      SendUserResponse(c, errno.ConvertErr(err), -1, "")
      return
   }

   SendUserResponse(c, errno.Success, userID, token)
}

配置路由&开启api服务

douyin/cmd/api下编写main.go,在main.go中配置路由并且开启服务器如下:

package main

import (
   "douyin/cmd/api/handles"
   "douyin/cmd/api/middleware"
   "douyin/cmd/api/rpc"
   "douyin/pkg/tracer"
   "net/http"

   "github.com/cloudwego/kitex/pkg/klog"
   "github.com/gin-gonic/gin"
)

func Init() {
   // TODO
   tracer.InitJaeger("api")
   rpc.InitRPC()
}

func main() {

   Init()
   r := gin.Default()
   r.Use(middleware.OpenTracing())
   r.Static("/static", "./public")
   douyin := r.Group("/douyin")

   userGroup := douyin.Group("/user")
   userGroup.POST("/login/", handlers.Login)
   userGroup.POST("/register/", handlers.Register)
   userGroup.GET("/", middleware.AuthMiddleware(), handlers.QueryCurUser)

   if err := http.ListenAndServe("0.0.0.0:8080", r); err != nil {
      klog.Fatal(err)
   }
}

app连接服务端测试

运行douyin/api下的脚本build.shbash ./build.sh 就能开启服务等待客户端抖声app的连接啦: sendpix5.jpg 在app中进行注册用户,注册成功,终端返回如下消息:

sendpix6.jpg 这样就完成了用户登录、注册和返回用户信息,如果后续选择社交方向将继续增加用户信息中关注数量和列表等。

3.github仓库地址

github.com/LaiYuShuang…