当前位置: 首页 > news >正文

Go-zero(api部分)

目录

api的语法:

type:用于定义请求/响应体

service:定义HTTP服务

@server:控制生成HTTP服务时候的meta信息

根据api文档生成最小HTTP服务

目录结构

api响应封装


api的语法:

首先定义一个api文档

type:用于定义请求/响应体
type LoginRequest {Username string `json:"username"`Password string `json:"password"`
}type UserInfoResponse {UserId   uint   `json:"userId"`Username string `json:"username"`
}

其中LoginRequest表示登录的请求体,要求包含string类型的username和password

语法类似于go的type struct

也支持写在一起

type(LoginRequest {Username string `json:"username"`Password string `json:"password"`}UserInfoResponse {UserId   uint   `json:"userId"`Username string `json:"username"`}
)

效果是一样的

service:定义HTTP服务
service users {@handler loginpost /login (LoginRequest) returns (string)
}

service users表示定义了一个名称为users的微服务,最后的入口文件名称也会是users.go

@handler 用于对生成的文件和方法命名

post /login (LoginRequest) returns (string)

  • post:表示这是一个post请求
  • /login:表示请求路由
  • (Request) returns (Response) 表示根据Request请求体,返回响应体Response,样例中的就是根据LoginRequest登录请求体返回一个字符串,当然这个后面也是可以自定义的,也可以不需要请求体,写法就是这样post /login  returns (string)
@server:控制生成HTTP服务时候的meta信息
@server (prefix: /api/usersjwt:    Auth
)

比如说prefix: /api/users 对该定义后面的services都加上路由前缀/api/users

jwt: Auth用于jwt鉴权(目前自己测试使用只成功了token的创建,token解析还没有成功)

目前支持的功能

  1. 路由分组
  2. 中间件声明
  3. 路由前缀
  4. 超时配置
  5. jwt 鉴权开关

如果需要对多个服务设置不同的meta信息

则可以这样写

type(LoginRequest {Username string `json:"username"`Password string `json:"password"`}UserInfoResponse {UserId   uint   `json:"userId"`Username string `json:"username"`}
)@server (prefix: /api/users
)
service users {@handler loginpost /login (LoginRequest) returns (string)
}@server (prefix: /api/usersjwt:    Auth
)
service users {@handler userInfoget /info returns (UserInfoResponse)
}//goctl api go -api user.api -dir .

第一个server管理login服务

第二个server管理userInfo服务

根据api文档生成最小HTTP服务

生成代码:

goctl api go -api user.api -dir .

goctl为关键字。api go,表示根据api文档生成go文档,-api用于指定api文件的位置这里的位置为(当前目录下的user.api文件,-dir用于指定go文档的生成位置,"."表示在当前目录下生成

目录结构

最终会在指定位置生成这样一个目录结构:

从上到下一个一个解释的话:

  • etc/user.yaml:用来保存基础的配置文件服务名称,主机地址,以及端口号
  • internal/config/config.go:主要用于加载保存user.yaml中的的数据以供使用
  • hander/loginhandler.go:用于处理login请求,过程大概就是下面这样的
func loginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {//提取请求中保存的请求体,如果没有相应的请求体数据,则返回错误信息var req types.LoginRequestif err := httpx.Parse(r, &req); err != nil {httpx.ErrorCtx(r.Context(), w, err)return}//调用请求处理函数,返回响应结果l := logic.NewLoginLogic(r.Context(), svcCtx)resp, err := l.Login(&req)//根据响应结果返回响应数据if err != nil {httpx.ErrorCtx(r.Context(), w, err)} else {httpx.OkJsonCtx(r.Context(), w, resp)}}
}
  • handler/router.go:主要保存路由信息
  • logic/loginlogic.go和logic/userinfologic:数据处理函数,供handler中的方法调用
  • svc/servicontext.go:返回一个携带配置信息的上下文
  • types/types.go:用于存放实体类
  • user.go:程序入口

整体的一个运行流程差不多为:

从user.go开始读取users.yaml配置文件,并将内保存到config.go文件中

根据handler/routers.go中的路由加载路由配置,然后启动服务

接受到对应的请求后就会调用handler中对应的方法,handler会调用logic的具体处理业务,处理完成后返回处理结果,并响应数据

因此对数据的一些特殊处理也都可以在handler中实现

api响应封装

将所有的响应都封装为一个统一的格式

func Response(r *http.Request, w http.ResponseWriter, res any, err error) {body := Body{}if err != nil {body = Body{Code: 10086,Data: nil,Msg:  "请求错误",}} else {body = Body{Code: 10086,Data: res,Msg:  "请求成功",}}//func WriteJson(w http.ResponseWriter, code int, v any)//将数据v写入到响应体response中httpx.WriteJson(w, http.StatusOK, body)}

就可以自己写好一个Response方法,然后插入到handler方法中

func loginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {//提取请求中保存的请求体,如果没有相应的请求体数据,则返回错误信息var req types.LoginRequestif err := httpx.Parse(r, &req); err != nil {httpx.ErrorCtx(r.Context(), w, err)return}//调用请求处理函数,返回响应结果l := logic.NewLoginLogic(r.Context(), svcCtx)resp, err := l.Login(&req)response.Response(r, w, resp, err)//根据响应结果返回响应数据//if err != nil {//	httpx.ErrorCtx(r.Context(), w, err)//} else {//	httpx.OkJsonCtx(r.Context(), w, resp)//}}
}

唯一麻烦的就是需要一个一个去加

官方本身也提供了一个这样的封装

type (Response {Code int    `json:"code"`Msg  string `json:"msg"`}
)type (UserInfo {UserId   uint   `json:"userId"`Username string `json:"username"`}
)type (UserInfoResponse {ResponseData UserInfo `json:"data"`}
)

写的结构和最终生成的实体类的结构也是一样的。

相关文章:

  • 导航【面试准备】
  • LLM多模态——GPT-4o改变人机交互的多模式 AI 模型应用
  • Predictable MDP Abstraction for Unsupervised Model-Based RL
  • Java面试题集
  • day16|二叉树的属性
  • Android App启动流程和源码详解
  • Flutter 中的 LicensePage 小部件:全面指南
  • 基于transformers框架实践Bert系列2--命名实体识别
  • 【因果推断从入门到精通二】随机实验3
  • 求第 N 个泰波那契数 | 动态规划
  • 教你用U-Mail搭建一个企业邮箱系统
  • ArcGIS Maps SDK for JS:使用queryFeatures方法查询 FeatureLayer 中符合条件的要素
  • 深入浅出:探索堆内存与分配器的奥秘
  • Vue.js Promise 与 async/await 的比较
  • MyBatisPlus使用流程
  • 【5+】跨webview多页面 触发事件(二)
  • Android 架构优化~MVP 架构改造
  • Angular数据绑定机制
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • React-Native - 收藏集 - 掘金
  • Sublime Text 2/3 绑定Eclipse快捷键
  • SwizzleMethod 黑魔法
  • text-decoration与color属性
  • 安卓应用性能调试和优化经验分享
  • 包装类对象
  • 近期前端发展计划
  • 前端自动化解决方案
  • 我这样减少了26.5M Java内存!
  • 学习JavaScript数据结构与算法 — 树
  • 学习笔记DL002:AI、机器学习、表示学习、深度学习,第一次大衰退
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​queue --- 一个同步的队列类​
  • ​马来语翻译中文去哪比较好?
  • ​油烟净化器电源安全,保障健康餐饮生活
  • # include “ “ 和 # include < >两者的区别
  • #、%和$符号在OGNL表达式中经常出现
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (24)(24.1) FPV和仿真的机载OSD(三)
  • (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令...
  • (C++二叉树05) 合并二叉树 二叉搜索树中的搜索 验证二叉搜索树
  • (javascript)再说document.body.scrollTop的使用问题
  • (react踩过的坑)Antd Select(设置了labelInValue)在FormItem中initialValue的问题
  • (创新)基于VMD-CNN-BiLSTM的电力负荷预测—代码+数据
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (一)Dubbo快速入门、介绍、使用
  • (译)2019年前端性能优化清单 — 下篇
  • (转)Linq学习笔记
  • (转载)Linux 多线程条件变量同步