最近在开发Go程序,同事( github.com/WiFeng/go-sky )参考go-kit框架封装了一个简易的轮子,包含了Api和Task任务,已经能满足大部分Web需求,依葫芦画瓢,自己理解了下,参考下图:
1:cmd/service.go
package main import ( "github.com/WiFeng/go-sky" "pkg/config" "pkg/endpoint" "pkg/service" "pkg/task" "pkg/transport/http" ) func main() { var ( service = service.New() endpoints = endpoint.New(service) httpHandler = http.NewHandler(endpoints) ) sky.LoadAppConfig(&config.GlobalAppConfig) sky.RegisterTask(task.Start, nil, true) sky.Run(httpHandler) }
初始化service、endpoint,NewHandler注册路由作为web服务,再注册Task运行后台任务。
2:pkg\endpoint\endpoint.go:
package endpoint import "pkg/service" type Endpoints struct { Article ArticleEndpoints } func New(s service.Service) Endpoints { return Endpoints{ Article: NewArticleEndpoints(s), } }
返回一个大的Endpoints,其中包含子的Endpoints,会将service.Service结构体传递给Endpoints。
3:pkg\endpoint\article.go:
package endpoint import ( "context" kitendpoint "github.com/go-kit/kit/endpoint" . "pkg/entity" "pkg/service" ) type ArticleEndpoints struct { MGet kitendpoint.Endpoint } func NewArticleEndpoints(s service.Service) ArticleEndpoints { return ArticleEndpoints{ MGet: MakeArticleMGetEndpoint(s), } } func MakeArticleMGetEndpoint(s service.Service) kitendpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { req := request.(ArticleInfoMGetRequest) return s.Article.MGet(ctx, req) } }
每一个子的Endpoint应该包含同一种类型的服务,最终调用对应的service服务方法。
不过ArticleInfoMGetRequest也可以在service\article.go(例子中注册在entity) 中定义。MakeArticleMGetEndpoint返回一个闭包,注册了一个路由。
4:pkg\entity\article.go
package entity type ArticleInfo struct { ArticleId int64 `json:"aid"` Uid int64 `json:"uid"` } type ArticleInfoMGetRequest struct { BaseRequest ArticleIds []int64 `json:"aids"` ForceNoCache bool `json:"force_no_cache"` } type ArticleInfoMGetRespData struct { Infos []ArticleInfo `json:"infos"` } type ArticleInfoMGetResponse struct { BaseResponse Data ArticleInfoMGetRespData `json:"data"` }
entity包含特定的工具方法。
5:pkg\service\service.go:
package service type Service struct { Article ArticleService } func New() Service { return Service{ Article: ArticleService{}, } }
service大结构体初始化,包括子service初始化。
6:pkg\service\article.go:
package service import ( "context" "pkg/dao" . "github.com/xiwujie/article/pkg/entity" ) type ArticleSyncJobRequest struct { BaseRequest Limit int `json:"limit"` JobName string `json:"job_name"` } type ArticleSyncJobResponse struct { BaseResponse } type ArticleService struct { } func (s *ArticleService) MGet(ctx context.Context, req ArticleInfoMGetRequest) (interface{}, error) { var resp ArticleInfoMGetResponse if req.ArticleIds == nil || len(req.ArticleIds) < 1 { return resp, nil } sdao = dao.NewSearchActivityTable(ctx) sdao.FetchById() return resp, nil }
具体的service服务,包含req,response的定义,也可以定义到 entry 目录下。
7:pkg/dao/article.go
package dao import ( "context" "database/sql" "fmt" skydb "github.com/WiFeng/go-sky/database" ) const ( searchActivityTableName = "" ) type SearchActivityTable struct { db *sql.DB } func NewSearchActivityTable(ctx context.Context) (*SearchActivityTable, error) { } func (t *SearchActivityTable) FetchById(ctx context.Context, id int) { }
dao方法,主要进行数据库等资源的操作。
8:pkg\transport\http\handler.go
func NewHandler(endpoints endpoint.Endpoints) http.Handler { r := skyhttp.NewRouter() genericOptions := []kithttp.ServerOption{ kithttp.ServerErrorEncoder(genericErrorEncoder), } r.Methods(http.MethodPost).Path(ArticleInfoMgetURI).Handler(skyhttp.NewServer( endpoints.Article.MGet, decodeHTTPArticleInfoMgetRequest, encodeHTTPGenericResponse, genericOptions..., )) return r }
注册http路由,endpoint作为参数传递给handler。