2.【go-kit教程】go-kit启动http服务
环境准备
- gokit工具集:
go get github.com/go-kit/kit
; - http请求路由组件:
go get github.com/gorilla/mux
;
快速上手
-
上代码
package main import ( "context" "encoding/json" "errors" "log" "net/http" "github.com/gorilla/mux" httptransport "github.com/go-kit/kit/transport/http" "github.com/go-kit/kit/endpoint" ) type MyService interface { Foo(context.Context, string) (string, error) Bar(context.Context, int64) (bool, error) } type myService struct{} func (s myService) Foo(ctx context.Context, str string) (string, error) { return "foo" + str, nil } func (s myService) Bar(ctx context.Context, n int64) (bool, error) { return n%2 == 0, nil } type fooRequest struct { Str string `json:"str"` } type fooResponse struct { Str string `json:"str"` Err string `json:"err,omitempty"` } type barRequest struct { N int64 `json:"n"` } type barResponse struct { Result bool `json:"result"` Err string `json:"err,omitempty"` } func makeFooEndpoint(svc MyService) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(fooRequest) res, err := svc.Foo(ctx, req.Str) if err != nil { return fooResponse{res, err.Error()}, nil } return fooResponse{res, ""}, nil } } func makeBarEndpoint(svc MyService) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(barRequest) res, err := svc.Bar(ctx, req.N) if err != nil { return barResponse{res, err.Error()}, nil } return barResponse{res, ""}, nil } } func decodeFooRequest(_ context.Context, r *http.Request) (interface{}, error) { var req fooRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { return nil, err } return req, nil } func decodeBarRequest(_ context.Context, r *http.Request) (interface{}, error) { var req barRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { return nil, err } return req, nil } func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { return json.NewEncoder(w).Encode(response) } func main() { // Create a new service svc := myService{} // Create the endpoints fooEndpoint := makeFooEndpoint(svc) barEndpoint := makeBarEndpoint(svc) // Create the router and register the endpoints r := mux.NewRouter() r.Methods("POST").Path("/foo").Handler(httptransport.NewServer( fooEndpoint, decodeFooRequest, encodeResponse, )) r.Methods("POST").Path("/bar").Handler(httptransport.NewServer( barEndpoint, decodeBarRequest, encodeResponse, )) // Start the server log.Fatal(http.ListenAndServe(":8080", r)) }
-
执行命令
curl http://127.0.0.1:8080/foo -d '{"data":"111"}' -XPOST
响应{"str":"foo"}
代码分层
-
目录结构
. ├── endpoints │ └── my_endpoint.go ├── go.mod ├── go.sum ├── main.go ├── services │ └── my_service.go └── transports └── my_transport.go
-
services/my_service.go
/** * @date: 2023/2/18 * @desc: 服务层 业务具体实现 */ package endpoints import "context" type MyServicer interface { Foo(context.Context, string) (string, error) Bar(context.Context, int64) (bool, error) } type MyService struct{} func (s *MyService) Foo(ctx context.Context, str string) (string, error) { return "foo" + str, nil } func (s *MyService) Bar(ctx context.Context, n int64) (bool, error) { return n%2 == 0, nil }
-
endpoints/endpoint.go
/** * @date: 2023/2/18 * @desc: endpoints 层 */ package endpoints import ( "context" "github.com/go-kit/kit/endpoint" services "kit-demo/services" ) type FooRequest struct { Str string `json:"str"` } type FooResponse struct { Str string `json:"str"` Err string `json:"err,omitempty"` } type BarRequest struct { N int64 `json:"n"` } type BarResponse struct { Result bool `json:"result"` Err string `json:"err,omitempty"` } func MakeFooEndpoint(svc services.MyServicer) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(FooRequest) res, err := svc.Foo(ctx, req.Str) if err != nil { return FooResponse{res, err.Error()}, nil } return FooResponse{res, ""}, nil } } func MakeBarEndpoint(svc services.MyServicer) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(BarRequest) res, err := svc.Bar(ctx, req.N) if err != nil { return BarResponse{res, err.Error()}, nil } return BarResponse{res, ""}, nil } }
-
transports/my_transport.go
/** * @date: 2023/2/18 * @desc: 传输层 http/rpc... */ package endpoints import ( "context" "encoding/json" "github.com/go-kit/kit/endpoint" httptransport "github.com/go-kit/kit/transport/http" "github.com/gorilla/mux" "kit-demo/endpoints" "net/http" ) func decodeFooRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.FooRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { return nil, err } return req, nil } func decodeBarRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.BarRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { return nil, err } return req, nil } func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { return json.NewEncoder(w).Encode(response) } // MakeHttpHandler make http handler use mux func MakeHttpHandler(ctx context.Context, fooEndpoint, barEndpoint endpoint.Endpoint) http.Handler { r := mux.NewRouter() options := []httptransport.ServerOption{ httptransport.ServerErrorEncoder(httptransport.DefaultErrorEncoder), } r.Methods("POST").Path("/foo").Handler(httptransport.NewServer( fooEndpoint, decodeFooRequest, encodeResponse, options..., )) r.Methods("POST").Path("/bar").Handler(httptransport.NewServer( barEndpoint, decodeBarRequest, encodeResponse, options..., )) return r }
-
main.go
package main import ( "context" "fmt" "kit-demo/endpoints" services "kit-demo/services" transports "kit-demo/transports" "net/http" "os" "os/signal" "syscall" ) func main() { errChan := make(chan error) // Create a new service svc := services.MyService{} ctx := context.Background() // Create the endpoints fooEndpoint := endpoints.MakeFooEndpoint(&svc) barEndpoint := endpoints.MakeBarEndpoint(&svc) r := transports.MakeHttpHandler(ctx, fooEndpoint, barEndpoint) go func() { fmt.Println("Http Server start at port:8080") handler := r errChan <- http.ListenAndServe(":8080", handler) }() go func() { c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) errChan <- fmt.Errorf("%s", <-c) }() fmt.Println(<-errChan) }