gozero基础-4.api服务

api语法

api文件就是对这个服务所有api的描述

服务名,函数名,路径,请求方法,请求参数,响应参数

我们以用户管理的两个重要接口为例,去编写它的api文件

type LoginRequest {
  UserName string `json:"userName"`
  Password string `json:"password"`
}

type Response {
  Code int    `json:"code"`
  Data string `json:"data"`
  Msg  string `json:"msg"`
}

type UserInfo {
  UserName string `json:"userName"`
  Addr     string `json:"addr"`
  Id       uint   `json:"id"`
}

type UserInfoResponse {
  Code int      `json:"code"`
  Data UserInfo `json:"data"`
  Msg  string   `json:"msg"`
}

service users {
  @handler login
  post /api/users/login (LoginRequest) returns (Response)
  
  @handler userInfo
  get /api/users/info returns (UserInfoResponse)
}

// goctl api go -api v1.api -dir .

通过这个示例,我们发现实际操作起来还是有些问题

  1. 响应如何封装?
  2. 统一api前缀
  3. 用户信息接口应该要进行jwt验证
  4. api文档

响应封装

不把code,data,msg写在api里面,我们通过封装统一响应

在统一响应里面去加上code data msg

type LoginRequest {
  UserName string `json:"userName"`
  Password string `json:"password"`
}

type UserInfoResponse {
  UserName string `json:"userName"`
  Addr     string `json:"addr"`
  Id       uint   `json:"id"`
}

service users {
  @handler login
  post /login (LoginRequest) returns (string)
  
  @handler userInfo
  get /info returns (UserInfoResponse)
}

// goctl api go -api v1.api -dir .

在common/response/enter.go中

package response

import (
  "github.com/zeromicro/go-zero/rest/httpx"
  "net/http"
)

type Body struct {
  Code uint32      `json:"code"`
  Msg  string      `json:"msg"`
  Data interface{} `json:"data"`
}

// Response http返回
func Response(r *http.Request, w http.ResponseWriter, resp interface{}, err error) {
  if err == nil {
    //成功返回
    r := &Body{
      Code: 0,
      Msg:  "成功",
      Data: resp,
    }
    httpx.WriteJson(w, http.StatusOK, r)
    return
  }
  //错误返回
  errCode := uint32(10086)
  // 可以根据错误码,返回具体错误信息
  errMsg := "服务器错误"

  httpx.WriteJson(w, http.StatusBadRequest, &Body{
    Code: errCode,
    Msg:  errMsg,
    Data: nil,
  })

}

修改一下handler的响应逻辑

l := logic.NewLoginLogic(r.Context(), svcCtx)
resp, err := l.Login(&req)
response.Response(r, w, resp, err)

然后完善逻辑即可

func (l *LoginLogic) Login(req *types.LoginRequest) (resp string, err error) {
  // todo: add your logic here and delete this line
  fmt.Println(req.UserName, req.Password)
  return "xxxx.xxxx.xxx", nil
}

模板定制化

当然官方提供了修改模板的方式,避免每次生成都要去改

模板定制化 | go-zero Documentation

先全局搜一下 handler.tpl这个文件

如果没有就先用这个命令生成

goctl template init

修改为:

package handler

import (
    "net/http"
    "github.com/zeromicro/go-zero/rest/httpx"
    "go_test/common/response"
    {{.ImportPackages}}
)

func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        {{if .HasRequest}}var req types.{{.RequestType}}
        if err := httpx.Parse(r, &req); err != nil {
            httpx.Error(w, err)
            return
        }{{end}}

        l := logic.New{{.LogicType}}(r.Context(), svcCtx)
        {{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}})
        {{if .HasResp}}response.Response(r, w, resp, err){{else}}response.Response(r, w, nil, err){{end}}

    }
}

api前缀

对于用户服务而言,api的前缀都是 /api/users

@server (
    prefix: /api/users
)
service users {
    @handler login
    post /login (LoginRequest) returns (string)

    @handler userInfo
    get /info returns (UserInfoResponse)
}

jwt及验证

type LoginRequest {
  UserName string `json:"userName"`
  Password string `json:"password"`
}

type UserInfoResponse {
  UserName string `json:"userName"`
  Addr     string `json:"addr"`
  Id       uint   `json:"id"`
}

@server(
  prefix: /api/users
)
service users {
  @handler login
  post /login (LoginRequest) returns (string)
}


@server(
  jwt: Auth
  prefix: /api/users
)
service users {
  @handler userInfo
  get /info returns (UserInfoResponse)
}

转换之后,修改配置文件

AccessExpire的单位是秒

Name: users
Host: 0.0.0.0
Port: 8888
Auth:
  AccessSecret: duerueudfnd235sdh
  AccessExpire: 3600

jwt公共代码

package jwts

import (
  "errors"
  "github.com/golang-jwt/jwt/v4"
  "time"
)

// JwtPayLoad jwt中payload数据
type JwtPayLoad struct {
  UserID   uint   `json:"user_id"`
  Username string `json:"username"` // 用户名
  Role     int    `json:"role"`     // 权限  1 普通用户  2 管理员
}

type CustomClaims struct {
  JwtPayLoad
  jwt.RegisteredClaims
}

// GenToken 创建 Token
func GenToken(user JwtPayLoad, accessSecret string, expires int64) (string, error) {
  claim := CustomClaims{
    JwtPayLoad: user,
    RegisteredClaims: jwt.RegisteredClaims{
      ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * time.Duration(expires))),
    },
  }

  token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim)
  return token.SignedString([]byte(accessSecret))
}

// ParseToken 解析 token
func ParseToken(tokenStr string, accessSecret string, expires int64) (*CustomClaims, error) {

  token, err := jwt.ParseWithClaims(tokenStr, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
    return []byte(accessSecret), nil
  })
  if err != nil {
    return nil, err
  }
  if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
    return claims, nil
  }
  return nil, errors.New("invalid token")
}


在登录成功之后签发jwt

loginlogic.go


func (l *LoginLogic) Login(req *types.LoginRequest) (resp string, err error) {
  // todo: add your logic here and delete this line
  auth := l.svcCtx.Config.Auth
  token, err := jwts.GenToken(jwts.JwtPayLoad{
    UserID:   1,
    Username: "枫枫",
    Role:     1,
  }, auth.AccessSecret, auth.AccessExpire)
  if err != nil {
    return "", err
  }
  return token, err
}


然后在userinfologic里面加上必要的逻辑

func (l *UserInfoLogic) UserInfo() (resp *types.UserInfoResponse, err error) {
  // todo: add your logic here and delete this line

  userId := l.ctx.Value("user_id").(json.Number)
  fmt.Printf("%v, %T, \n", userId, userId)
  username := l.ctx.Value("username").(string)
  uid, _ := userId.Int64()

  return &types.UserInfoResponse{
    UserId:   uint(uid),
    Username: username,
  }, nil
}


userinfo这个接口就已经自动加上jwt的验证了

不过这个token是需要这样加

headers:{
  Authorization: "Bearer token"
}

没有通过jwt的响应是401,这个需要留意一下

当然,也能修改jwt验证的响应

在main中,加上jwt验证的回调函数即可

func main() {
  flag.Parse()

  var c config.Config
  conf.MustLoad(*configFile, &c)

  server := rest.MustNewServer(c.RestConf, rest.WithUnauthorizedCallback(JwtUnauthorizedResult))
  defer server.Stop()

  ctx := svc.NewServiceContext(c)
  handler.RegisterHandlers(server, ctx)

  fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
  server.Start()
}

// JwtUnauthorizedResult jwt验证失败的回调
func JwtUnauthorizedResult(w http.ResponseWriter, r *http.Request, err error) {
  fmt.Println(err) // 具体的错误,没带token,token过期?伪造token?
  httpx.WriteJson(w, http.StatusOK, response.Body{10087, "鉴权失败", nil})
}

生成api文档

后端对外的api,肯定要和前端进行对接

那么在go-zero里面怎么生成api接口文档呢

  1. 安装goctl-swagger
go install github.com/zeromicro/goctl-swagger@latest
  1. 生成app.json

如果没有doc目录,需要创建

goctl api plugin -plugin goctl-swagger="swagger -filename app.json -host localhost:8888 -basepath /" -api v1.api -dir ./doc
  1. 使用docker,查看这个swagger页面
docker run -d --name swag -p 8087:8080 -e SWAGGER_JSON=/opt/app.json -v D:\IT\go_project3\go_test\v1\api\doc\:/opt swaggerapi/swagger-ui

可以再完善下api信息

@server(
  prefix: /api/users
)
service users {
  @doc(
    summary: "用户登录"
  )
  @handler login
  post /login (LoginRequest) returns (string)
}

@server(
  jwt: Auth
  prefix: /api/users
)
service users {
  @doc(
    summary: "获取用户信息"
  )
  @handler userInfo
  get /info returns (UserInfoResponse)
}

改为再重新生成一下 json

但是,我发现这个swagger体验不怎么好,使用了自定义响应之后,swag这里改不了

公司项目的话,都是有自己的api平台

团队项目的话,也可以用apifox

所以,个人用swagger的话,凑活着用也不是不行

参考文档

api语法 go-zero 基础 -- 框架设计_go-zero doc-优快云博客

官方api规范 API 规范 | go-zero Documentation

go-zero使用jwt go-zero学习 — 进阶_go-zero nacos-优快云博客

自定义jwt错误 go-zero鉴权(jwt)失败回调函数错误处理-优快云博客

goctl-swagger的坑 go-zero插件goctl-swagger的坑 - 丶吃鱼的猫 - 博客园

goctl-swagger使用 goctl-swagger的使用方法-优快云博客

<think>好的,我需要处理用户关于goctl命令的问题,特别是关于`goctl model mysql datasource`命令的参数解释、使用方法和示例。用户还提供了一个具体的URL示例和相关参数,如root密码、TCP地址、端口、数据库名和模板目录。 首先,我得回忆一下goctl的文档。goctl是Go Zero框架的一个代码生成工具,用于快速生成模型、API等代码。其中,`model`子命令用于数据库模型的生成,而`mysql datasource`则是从MySQL数据源生成模型。 用户提到的命令参数应该包括数据库连接信息,比如URL、用户名、密码、主机、端口、数据库名,以及可能的模板目录。我需要确认各个参数的名称和用法。例如,`-url`通常用于JDBC格式的连接字符串,但goctl可能有自己的参数格式,比如分开指定主机、端口、用户名、密码等。 接下来,我需要解析用户提供的参数:URL是`root:woshi566@tcp(127.0.0.1:3306)/flopsdb`,模板目录是`templates/dir/model`。这可能对应到goctl的参数,比如`-url`参数需要包含用户名、密码、协议、地址、端口和数据库名。但要注意goctl是否使用特定的格式,比如是否使用`@tcp`部分,或者是否需要转义特殊字符。 另外,用户提供的引用内容中有关于Spring的数据库配置示例,比如`spring.datasource.url=jdbc:mysql://...`,但goctl可能使用不同的参数格式,比如直接指定各个部分而不是JDBC URL。需要确认goctl的参数是否需要分开指定主机、端口等,还是允许一个完整的URL。 可能的参数包括: - `-url`:完整的数据库连接字符串,格式可能为`user:password@tcp(host:port)/dbname` - `-cache`:是否启用缓存 - `-dir`:生成代码的输出目录 - `-style`:代码风格(如gozero- `-tpl`:自定义模板目录 用户示例中的`templates/dir/model`应该是`-tpl`参数的值,用于指定自定义模板的位置。而生成的模型代码输出目录可能由`-dir`指定,但用户示例中没有明确提到,可能需要补充。 需要确保提供的示例命令正确拼写参数,并正确转义特殊字符,比如密码中的特殊符号是否需要引号包裹。例如,如果密码中有`@`符号,可能需要用引号括起来。 总结步骤: 1. 解释`goctl model mysql datasource`命令的作用:生成MySQL数据库的模型代码。 2. 列出常用参数及其含义,如`-url`、`-dir`、`-cache`、`-style`、`-tpl`。 3. 提供具体示例命令,使用用户提供的参数值,并说明各部分的替换方法。 4. 注意可能的问题点,如密码中的特殊字符处理,模板目录的路径格式。 5. 确保引用正确的文档或参考资料,如Go Zero的官方文档或用户提供的引用中的数据库连接格式。 可能的问题:用户提供的引用是关于Spring的配置,可能与goctl的参数格式不同,需要明确区分,避免混淆。例如,goctl的URL参数格式可能更接近Go语言的数据库连接字符串,而不是JDBC的格式。 最后,生成相关问题,可能涉及其他子命令、参数的高级用法、自定义模板的编写等。</think>### goctl model mysql datasource 命令详解 #### 1. 命令功能 用于从MySQL数据源自动生成Go语言数据模型代码,支持自定义模板和缓存配置[^1]。 #### 2. 核心参数解析 | 参数名称 | 参数格式 | 说明 | |---------|---------|------| | `-url` | `user:password@tcp(ip:port)/dbname` | 数据库连接字符串 | | `-dir` | 文件路径 | 生成代码的输出目录 | | `-cache` | `true`/`false` | 是否启用Redis缓存(默认false) | | `-style` | 样式名称 | 代码格式规范(默认gozero) | | `-tpl` | 模板路径 | 自定义模板目录 | #### 3. 使用示例 根据您的参数要求,完整命令如下: ```bash goctl model mysql datasource -url="root:woshi566@tcp(127.0.0.1:3306)/flopsdb" -dir=./model -tpl=templates/dir/model ``` #### 4. 参数说明 1. **连接字符串解析** `root:woshi566@tcp(127.0.0.1:3306)/flopsdb` 对应: - 用户名: `root` - 密码: `woshi566` - 协议: `tcp` - 地址: `127.0.0.1:3306` - 数据库: `flopsdb` 2. **模板目录** 使用`-tpl`参数指定自定义模板路径,支持覆盖默认模板实现个性化代码生成[^2]。 3. **特殊字符处理** 若密码包含`@`等特殊字符,建议使用URL编码: ```bash goctl model mysql datasource -url="root:wosh%40566@tcp(localhost:3306)/flopsdb" ``` #### 5. 生成文件结构 执行后将生成如下文件: ``` ./model ├── flopsdbmodel.go # 数据模型定义 └── vars.go # 数据库连接配置 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值