前言
在使用go开发http服务的时候,我们会频繁的定义请求和返回结构体,还有路由,很浪费时间。那有没有一种方法可以让我们避免这种频繁或者减少频率呢。protoc-gen-hip帮助我们解决了这个问题。基于protobuffer去生成自动生成我们需要的api代码逻辑
如何使用
下载工具
- 下载protoc
首先需要下载protoc mac系统:brew install protoc
- 下载protoc-gen-hip
// go 1.17以前
go get -u github.com/GodWY/protoc-gen-hip@latest go install github.com/GodWY/protoc-gen-hip
// go1.17后
go install github.com/GodWY/protoc-gen-hip@latest
定义protobuffer
定义请求
syntax="proto3";
package account;
option go_package="pkg/gen/http/account";
message SendSmsCodeRQ {
// @gotags: json:"phone_num"
string PhoneNum = 1;
}
message SendSmsCodeRS {
}
定义http服务
//@import:xxx.xxx.xxx @import:xxx.xxxx.xxxx
//@middle:xxx.Has()
//@root:/api/xx
service Account{
//@method:POST @middle:xxx.Has()
rpc SendSmsCode(SendSmsCodeRQ) returns (SendSmsCodeRS);
}
执行代码生成
protoc - --proto_path=. --hip_out=./ --go_out=./ ./proto/*.proto
生成的代码
// Code generated by protoc-gen-go-hip. DO NOT EDIT.
// versions:v1.2.0
package account
// This is a compile-time assertion to ensure that this generated file
// is compatible with the kratos package it is being compiled against.
import (
"net/http"
"github.com/GodWY/gutil"
"xxx.xxx.xxx"
"github.com/gin-gonic/gin"
)
// generated http method
func registerAccountHttpHandler(srv *gin.Engine, srvs AccountHttpHandler) {
group := srv.Group("/api/account", xxx.Has())
group.POST("/v1/sendSmsCode", srvs.SendSmsCode, xxx.Has())
group.POST("/v1/accessLogin", srvs.AccessLogin)
}
var TAccount Account
func RegisterAccountHttpHandler(srv *gin.Engine, srvs Account) {
tmp := new(xxx_Account)
registerAccountHttpHandler(srv, tmp)
TAccount = srvs
}
type Account interface {
SendSmsCode(ctx *gin.Context, in *SendSmsCodeRQ) (out *SendSmsCodeRS, err error)
AccessLogin(ctx *gin.Context, in *AccessLoginRQ) (out *AccessLoginRS, err error)
}
// generated http handle
type AccountHttpHandler interface {
SendSmsCode(ctx *gin.Context)
AccessLogin(ctx *gin.Context)
}
type xxx_Account struct {
}
func (xx *xxx_Account) SendSmsCode(ctx *gin.Context) {
req := &SendSmsCodeRQ{}
if ok := ctx.Bind(req); ok != nil {
detail := "bind request error"
rt := gutil.RetFail(10000, detail)
ctx.JSON(http.StatusOK, rt)
return
}
rsp, err := TAccount.SendSmsCode(ctx, req)
if err != nil {
ctx.JSON(http.StatusOK, gutil.RetError(err))
return
}
ctx.JSON(http.StatusOK, gutil.RetSuccess("success", rsp))
}
func (xx *xxx_Account) AccessLogin(ctx *gin.Context) {
req := &AccessLoginRQ{}
if ok := ctx.Bind(req); ok != nil {
detail := "bind request error"
rt := gutil.RetFail(10000, detail)
ctx.JSON(http.StatusOK, rt)
return
}
rsp, err := TAccount.AccessLogin(ctx, req)
if err != nil {
ctx.JSON(http.StatusOK, gutil.RetError(err))
return
}
ctx.JSON(http.StatusOK, gutil.RetSuccess("success", rsp))
}
注释说明
5. 支持导入三方包,自定义中间件和自定义路由
> 所有的自定义代码都是通过注释读取的。
- 自定义组中间件
> 每一个service对应gin都是一个组,定义组路由只需要使用`@middle:`关键字即可,value是对应的方法
- 导入项目包
> 在service中定义 `@import` 可以连续定义多个导入包
- 定义接口请求
> 在每个rpc接口中,自定义请求方法 `@method` 即可目前支持GET,POST,ANY 不区分大小写
- 定义接口中间件
> 在接口注释中 `@middle` 即可定义自定义和gin中间件
- 如何自定义组路由
> 在service 定义`@root`即可
使用
```
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
type AccSrc struct {
}
func (a AccSrc) SendSmsCode(ctx *gin.Context, in *account.SendSmsCodeRQ) (out *account.SendSmsCodeRS, err error) {
panic("implement me")
}
func (a AccSrc) AccessLogin(ctx *gin.Context, in *account.AccessLoginRQ) (out *account.AccessLoginRS, err error) {
panic("implement me")
}
func main() {
en := gin.New()
ac:=&AccSrc{}
account.RegisterAccountHttpHandler(en,ac)
en.Run(":8081")
}
func Logger() gin.HandlerFunc {
return func(context *gin.Context) {
fmt.Printf("xxxxxx1")
}
}
总结
我们利用pb来实现路由的生成可以帮助我们快速的生成http代码