软文网站模板网站建设陆金手指下拉壹玖
news/
2025/9/22 19:41:03/
文章来源:
软文网站模板,网站建设陆金手指下拉壹玖,广州网站建设公司小程序,商品展示软件提示#xff1a; 所有体系课见专栏#xff1a;Go 项目开发极速入门实战课#xff1b;欢迎加入我的训练营#xff1a;云原生AI实战营#xff0c;一个助力 Go 开发者在 AI 时代建立技术竞争力的实战营#xff1b;本节课最终源码位于 fastgo 项目的 feature/s14 分支#x… 提示 所有体系课见专栏Go 项目开发极速入门实战课欢迎加入我的训练营云原生AI实战营一个助力 Go 开发者在 AI 时代建立技术竞争力的实战营本节课最终源码位于 fastgo 项目的 feature/s14 分支更详细的课程版本见Go 项目开发中级实战课27 | 业务实现4实现 Handler 层代码 fastgo 三层简洁架构开发的最后一步便是开发 Handler 层代码。Handler 层代码的实现思路和 Biz 层、Store 层保持一致。
Handler 实现
要实现 Handler主要分为以下几步
实现创建 Handler 层实例的方法实现用户相关 Handler 方法对请求参数进行校验初始化 Handler。
步骤 1实现创建 Handler 层实例的方法
HTTP API 接口最终的逻辑是由 Handler 方法来实现的。所以需要先实现 Handler 方法。
fastgo 项目的 Handler 层代码位于 internal/apiserver/handler/ 目录中。新建一个 Handler 结构体该结构体包含了 fg-apiserver 的路由函数。代码位于 internal/apiserver/handler/handler.go 文件中内容如下
package handlerimport (github.com/onexstack/fastgo/internal/apiserver/biz
)// Handler 处理博客模块的请求.
type Handler struct {biz biz.IBiz
}// NewHandler 创建新的 Handler 实例.
func NewHandler(biz biz.IBiz) *Handler {return Handler{biz: biz,}
}Handler 结构体中包含了 Biz 层的 IBiz 接口IBiz 接口中包含的方法用来执行具体的业务逻辑。:
步骤 2 实现用户相关 Handler 方法
internal/apiserver/handler/user.go 文件中包含了用户相关的 Handler 方法。这些 Handler 方法的实现逻辑保持一致。实现逻辑如下 这里我介绍下 CreateUser 路由方法的实现其他路由实现方法类似。CreateUser 路由方法代码如下
// CreateUser 创建新用户.
func (h *Handler) CreateUser(c *gin.Context) {slog.Info(Create user function called)var rq v1.CreateUserRequestif err : c.ShouldBindJSON(rq); err ! nil {core.WriteResponse(c, errorsx.ErrBind, nil)return}if err : validation.ValidateCreateUserRequest(c.Request.Context(), rq); err ! nil {core.WriteResponse(c, errorsx.ErrInvalidArgument.WithMessage(err.Error()), nil)return}resp, err : h.biz.UserV1().Create(c.Request.Context(), rq)if err ! nil {core.WriteResponse(c, err, nil)return}core.WriteResponse(c, nil, resp)
}首先调用 c.ShouldBindJSON 方法将请求中的参数解析到 v1.CreateUserRequest 类型的变量 rq 中。如果解析失败返回 errorsx.ErrBind 类型的自定义错误。
接着调用 validation.ValidateCreateUserRequest 函数对请求参数进行校验。为了统一管理请求参数的校验方法提高代码可维护性。将校验方法统一放在 validation位于 internal/apiserver/pkg/validation 目录中。如果校验失败返回 errorsx.ErrInvalidArgument 类型的自定义错误。这里要注意传递的 context 是 c.Request.Context()而不是 *gin.Context 类型的变量 c。因为 c中缺少了一些 HTTP 请求上下文信息。
接着调用 Biz 层的方法 h.biz.UserV1().Create 执行具体的业务逻辑。
gin.Context 结构体类型提供了以下方法分别用来绑定不同位置的请求参数到结构体
ShouldBindJSONShouldBindUri将请求中的路径参数绑定到 Go 结构体中的对应字段上这些字段跟路径参数的映射关系是通过 Go 结构体字段的 uri 标签来映射的XXXX
步骤 3对请求参数进行校验
首先创建一个校验类型的结构体 Validator代码位于 internal/apiserver/pkg/validation/validation.go 文件中内容如下
// Validator 是验证逻辑的实现结构体.
type Validator struct {// 有些复杂的验证逻辑可能需要直接查询数据库// 这里只是一个举例如果验证时有其他依赖的客户端/服务/资源等// 都可以一并注入进来store store.IStore
}// NewValidator 创建一个新的 Validator 实例.
func NewValidator(store store.IStore) *Validator {return Validator{store: store}
}在 Validator 结构体中可以添加校验逻辑中依赖的依赖项。例如 store.IStore 类型的实例第三方微服务客户端等。以此实现更加复杂的校验逻辑。
ValidateCreateUserRequest 方法实现如下
func (v *Validator) ValidateCreateUserRequest(ctx context.Context, rq *v1.CreateUserRequest) error {// Validate usernameif rq.Username {return errors.New(Username cannot be empty)}if len(rq.Username) 4 || len(rq.Username) 32 {return errors.New(Username must be between 4 and 32 characters)}// Username can only contain letters, numbers, and underscoresusernameRegex : regexp.MustCompile(^[a-zA-Z0-9_]$)if !usernameRegex.MatchString(rq.Username) {return errors.New(Username can only contain letters, numbers, and underscores)}// Validate passwordif rq.Password {return errors.New(Password cannot be empty)}if len(rq.Password) 8 || len(rq.Password) 64 {return errors.New(Password must be between 8 and 64 characters)}// Validate password complexity (must contain at least one letter and one number)passwordRegex : regexp.MustCompile(^.*(?.*[a-zA-Z])(?.*\d).*$)if !passwordRegex.MatchString(rq.Password) {return errors.New(Password must contain at least one letter and one number)}// Validate nickname (if provided)if rq.Nickname ! nil *rq.Nickname ! {if len(*rq.Nickname) 32 {return errors.New(Nickname cannot exceed 32 characters)}}// Validate emailif rq.Email {return errors.New(Email cannot be empty)}emailRegex : regexp.MustCompile(^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}$)if !emailRegex.MatchString(rq.Email) {return errors.New(Invalid email format)}// Validate phone numberif rq.Phone {return errors.New(Phone number cannot be empty)}// Validate Chinese mainland phone number format (11 digits starting with 1)phoneRegex : regexp.MustCompile(^1\d{10}$)if !phoneRegex.MatchString(rq.Phone) {return errors.New(Invalid phone number format, must be 11 digits starting with 1)}return nil
}上述校验逻辑代码比较简单这里不再介绍。为了提高代码的可维护性将用户相关的校验方法统一保存在 internal/apiserver/pkg/validation/user.go 文件中。user.go 文件中只实现了 v1.CreateUserRequest 请求结构体的校验逻辑。
v1.UpdateUserRequest 等其他请求结构体的校验代码实现留个作业由你来实现。
步骤 4初始化 Handler
修改 internal/apiserver/server.go 文件添加以下代码
package apiserverimport (...github.com/onexstack/fastgo/internal/apiserver/bizgithub.com/onexstack/fastgo/internal/apiserver/handlergithub.com/onexstack/fastgo/internal/apiserver/pkg/validationgithub.com/onexstack/fastgo/internal/apiserver/store...
)
...
// NewServer 根据配置创建服务器.
func (cfg *Config) NewServer() (*Server, error) {...// 初始化数据库连接db, err : cfg.MySQLOptions.NewDB()if err ! nil {return nil, err}store : store.NewStore(db)cfg.InstallRESTAPI(engine, store)...
}在 NewServer 方法中通过调用 cfg.MySQLOptions.NewDB() 创建了一个 *gorm.DB 的实例 db再使用 db 创建了 store.IStore 的实例 store。
将路由安装代码在 cfg.InstallRESTAPI 方法中实现这样可以使 NewServer 更加简洁同时也便于统一维护路由设置。
cfg.InstallRESTAPI 方法实现如下
// 注册 API 路由。路由的路径和 HTTP 方法严格遵循 REST 规范.
func (cfg *Config) InstallRESTAPI(engine *gin.Engine, store store.IStore) {...// 创建核心业务处理器handler : handler.NewHandler(biz.NewBiz(store), validation.NewValidator(store))authMiddlewares : []gin.HandlerFunc{}// 注册 v1 版本 API 路由分组v1 : engine.Group(/v1){// 用户相关路由userv1 : v1.Group(/users){// 创建用户。这里要注意创建用户是不用进行认证和授权的userv1.POST(, handler.CreateUser)userv1.PUT(:userID, handler.UpdateUser) // 更新用户信息userv1.DELETE(:userID, handler.DeleteUser) // 删除用户userv1.GET(:userID, handler.GetUser) // 查询用户详情userv1.GET(, handler.ListUser) // 查询用户列表.}// 博客相关路由postv1 : v1.Group(/posts, authMiddlewares...){postv1.POST(, handler.CreatePost) // 创建博客postv1.PUT(:postID, handler.UpdatePost) // 更新博客postv1.DELETE(, handler.DeletePost) // 删除博客postv1.GET(:postID, handler.GetPost) // 查询博客详情postv1.GET(, handler.ListPost) // 查询博客列表}}
}在 InstallRESTAPI 方法中通过 handler.NewHandler 函数创建了 Handler 层的实例。并使用 Handler 的实例 handler 提供的路由方法来设置 HTTP 路由。
创建 handler 实例依赖 biz.IBiz、*validation.Validator 类型的实例。上述实例分别通过 biz.NewBiz(store)、validation.NewValidator(store) 函数来创建。
上述代码使用 Gin 框架提供的各类路由注册方法注册了符合 REST 规范的 HTTP 路由。Gin 框架如何注册路由请阅读 Gin GitHub 项目仓库的 README 文件。上述代码注册的 HTTP 路由见 下表所示。
HTTP 路由HTTP 方法 HTTP 路径路由描述GET /healthz健康检查接口POST /v1/users创建用户PUT /v1/users/:userID更新用户信息DELETE /v1/users/:userID删除用户GET /v1/users/:userID获取用户信息GET /v1/users列出所有用户POST /v1/posts创建文章PUT /v1/posts/:postID更新文章DELETE /v1/posts删除文章GET /v1/posts/:postID获取文章信息GET /v1/posts列出所有文章
编译并测试
执行以下命令重新编译并运行 fg-apiserver
$ ./build.sh
$ _output/fg-apiserver -c configs/fg-apiserver.yaml打开另一个 Linux 终端执行以下命令测试 HTTP 接口是否正常工作
$ curl -XPOST -HContent-Type: application/json http://127.0.0.1:6666/v1/users -d {username:colin,password:fastgo1234,nickname:belm,email:nosbelmqq.com,phone:1818888xxxx}
{userID:user-gxqfqn}上述命令创建了一个新的用户并返回了 用户 ID user-gxqfqn。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/910157.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!