go #源码分析 #v1.0.0 #学习
概述
这里我从 internal/apiserver/server.go 文件中的 initRouter(s.genericAPIServer.Engine) 代码进行路由的注册分析, 主要学习目标如何利用接口将 api 与 api server 进行分离.
apiserver.initRouter
internal/apiserver/router.go
这个函数只是一个引子函数, 用于调用 Middleware 和 api 初始化. 这里可以看出项目使用的内部路由框架由 gin 提供.
func initRouter(g *gin.Engine) {installMiddleware(g)installAPI(g)}
installMiddleware 函数是一个空函数, 我们不做分析. 下面进入 installAPI 分析其实现方式.
apiserver.installAPI
internal/apiserver/router.go
installAPI 是 API 处理函数与路由绑定注册的位置值. 下面对每组 API 的大致内容进行分析
func installAPI(g *gin.Engine) *gin.Engine {// Middlewares.jwtStrategy, _ := newJWTAuth().(auth.JWTStrategy)g.POST("/login", jwtStrategy.LoginHandler)g.POST("/logout", jwtStrategy.LogoutHandler)// Refresh time can be longer than token timeoutg.POST("/refresh", jwtStrategy.RefreshHandler)auto := newAutoAuth()g.NoRoute(auto.AuthFunc(), func(c *gin.Context) {core.WriteResponse(c, errors.WithCode(code.ErrPageNotFound, "Page not found."), nil)})// v1 handlers, requiring authenticationstoreIns, _ := mysql.GetMySQLFactoryOr(nil)v1 := g.Group("/v1"){// user RESTful resourceuserv1 := v1.Group("/users"){userHandler := user.NewUserHandler(storeIns)userv1.POST("", userHandler.Create)userv1.Use(auto.AuthFunc(), middleware.Validation())// v1.PUT("/find_password", userHandler.FindPassword)userv1.DELETE("", userHandler.DeleteCollection) // admin apiuserv1.DELETE(":name", userHandler.Delete) // admin apiuserv1.PUT(":name/change-password", userHandler.ChangePassword)userv1.PUT(":name", userHandler.Update)userv1.GET("", userHandler.List)userv1.GET(":name", userHandler.Get) // admin api}v1.Use(auto.AuthFunc())// policy RESTful resourcepolicyv1 := v1.Group("/policies", middleware.Publish()){policyHandler := policy.NewPolicyHandler(storeIns)policyv1.POST("", policyHandler.Create)policyv1.DELETE("", policyHandler.DeleteCollection)policyv1.DELETE(":name", policyHandler.Delete)policyv1.PUT(":name", policyHandler.Update)policyv1.GET("", policyHandler.List)policyv1.GET(":name", policyHandler.Get)}// secret RESTful resourcesecretv1 := v1.Group("/secrets", middleware.Publish()){secretHandler := secret.NewSecretHandler(storeIns)secretv1.POST("", secretHandler.Create)secretv1.DELETE(":name", secretHandler.Delete)secretv1.PUT(":name", secretHandler.Update)secretv1.GET("", secretHandler.List)secretv1.GET(":name", secretHandler.Get)}}return g}
- 第 3 - 7 行 jwt 中间件的 登陆, 登出, 刷新token API 的注册.
- 第 9 - 12 行 目前未知.
- 第 16 - 60 行 v1 版本的 api 注册.
- 第 19 - 32 行 用户api 注册.
- 第 37 - 47 行 策略api 注册.
- 第 50 -59 行 secret api 注册.
其中配置中间件和路由注册内容都是全部手动实现, 没有什么分析的必要, 下面对每个 Hnadler 进行学习。
Handler 学习
这里分析发现 handler 的结构设计比较巧妙这里, 先对其结构进行分析说明.
UserHandler
UserHandler 由 Service 和 Factory 两个接口组成. 这里的关键使用到了接口, Service 的实现和 Store 的实现可以随时替换!
type UserHandler struct {srv srvv1.Servicestore store.Factory}func NewUserHandler(store store.Factory) *UserHandler {return &UserHandler{srv: srvv1.NewService(store),store: store,}}
Service 接口
type Service interface {Users() UserSrvSecrets() SecretSrvPolicies() PolicySrv}
type UserSrv interface {Create(ctx context.Context, user *v1.User, opts metav1.CreateOptions) errorUpdate(ctx context.Context, user *v1.User, opts metav1.UpdateOptions) errorDelete(ctx context.Context, username string, opts metav1.DeleteOptions) errorDeleteCollection(ctx context.Context, usernames []string, opts metav1.DeleteOptions) errorGet(ctx context.Context, username string, opts metav1.GetOptions) (*v1.User, error)List(ctx context.Context, opts metav1.ListOptions) (*v1.UserList, error)ListWithBadPerformance(ctx context.Context, opts metav1.ListOptions) (*v1.UserList, error)ChangePassword(ctx context.Context, user *v1.User) error}
Factory 接口
type Factory interface {Users() UserStoreSecrets() SecretStorePolicies() PolicyStoreClose() error}
type UserStore interface {Create(ctx context.Context, user *v1.User, opts metav1.CreateOptions) errorUpdate(ctx context.Context, user *v1.User, opts metav1.UpdateOptions) errorDelete(ctx context.Context, username string, opts metav1.DeleteOptions) errorDeleteCollection(ctx context.Context, usernames []string, opts metav1.DeleteOptions) errorGet(ctx context.Context, username string, opts metav1.GetOptions) (*v1.User, error)List(ctx context.Context, opts metav1.ListOptions) (*v1.UserList, error)}
