2
头图

Overview of rest framework

Let by go-zero tool comes with a command line goctl to generate a api service , its main function is as follows:

func main() {
    flag.Parse()

    var c config.Config
    conf.MustLoad(*configFile, &c)

    ctx := svc.NewServiceContext(c)
    server := rest.MustNewServer(c.RestConf)
    defer server.Stop()

    handler.RegisterHandlers(server, ctx)

    fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
    server.Start()
}
  1. Parse the configuration file
  2. serviceContext configuration file and initialize 06168d29c2d409
  3. Initialize rest server
  4. context into server :

    1. Register routing
    2. the context the start endpoint simultaneously injected into router which
  5. Start server

Next, we will explain its design principles step by step! Let's Go!

web framework

From the daily development experience, a good web framework roughly needs to meet the following characteristics:

  1. Route matching/multi-route support
  2. Support custom middleware
  3. The framework and business development are completely decoupled, making it convenient for developers to develop quickly
  4. Parameter verification/matching
  5. Service self-checking functions such as monitoring/logging/indicator
  6. Service self-protection (fuse/current limit)

go-zero rest design

https://github.com/zeromicro/go-zero/tree/master/rest

Overview

  1. With the help of context (different from gin's context), initialize the resource → save it in serviveCtx and share it in the handler (as for resource pooling, hand it over to the resource to handle it, serviveCtx is just the entry and sharing point)
  2. Independent router declaration file, also joins the concept of router group, which is convenient for developers to organize the code structure
  3. Several built-in middleware: monitoring/fuse/authentication, etc.
  4. Using goctl codegen + option design pattern , it is convenient for developers to control the access of some middleware.

The above figure describes the mode of rest processing requests and most of the processing paths.

  1. The built-in middleware of the framework has helped developers solve most of the logic of service self-processing
  2. At the same time, go-zero also gives developers out-of-the-box components (dq, fx, etc.) business logic
  3. From the development mode to help developers only need to pay attention to their own business logic and the required resource preparation

Let us elaborate on how the rest is started?

Start the process

The figure above describes the modules and general flow of the overall server startup. Prepare to analyze the rest implementation according to the following process:

  1. Package and transformation based on http.server: engine (web framework core) and option
  2. Multi-route matching adopts radix-tree structure
  3. The middleware adopts the onion model → []Middleware
  4. http parse parsing and matching verification → httpx.Parse()
  5. createMetrics() ) and monitoring points (prometheus) will be collected during the request process

server engine package

Click on the big picture to watch

Engine runs through the entire server life cycle:

  1. The router will carry the path/handler defined by the developer, in the final router.handle()
  2. Registered custom middleware + framework middleware, executed before router handler logic

is here: the granularity of go-zero processing is on the route, and the encapsulation and processing are performed layer by layer on the route

Route matching

So when the request comes, how do you get to the routing layer in the first place?

First of all, in the development of the most primitive http server, there is such a piece of code:

type helloHandler struct{}

func (h *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello, world!"))
}

func main() {
    http.Handle("/", &helloHandler{})
    http.ListenAndServe(":12345", nil)
}

http.ListenAndServe() will be executed internally to: server.ListenAndServe()

Let's see how it is used in rest:

The incoming handler is actually the router generated by router.NewRouter(). This router carries the processing function set of the entire server.

At the same time, when the http.Server structure is initialized, the handler is injected into it:

type Server struct {
    ...
    Handler Handler
}

func start(..., handler http.Handler, run func(srv *http.Server) error) (err error) {
    server := &http.Server{
        Addr:    fmt.Sprintf("%s:%d", host, port),
        Handler: handler,
    }
    ...
    return run(server)
}

After http.Server receives req, the final execution is: handler.ServeHTTP(rw, req)

So the built-in router also needs to implement ServeHTTP . As for how the router itself implements ServeHTTP : it is nothing more than finding a matching route, and then executing the handle logic corresponding to the route.

Parsing parameters

Parsing parameters is the basic ability that the http framework needs to provide. In the code generated by goctl code gen, the handler layer has integrated the req argument parse function:

// generate by goctl
func QueryAllTaskHandler(ctx *svc.ServiceContext) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // custom request in .api file
        var req types.QueryAllTaskRequest
        // parse http request
        if err := httpx.Parse(r, &req); err != nil {
            httpx.Error(w, err)
            return
        }

        l := logic.NewEventLogic(r.Context(), ctx)
        resp, err := l.QueryAllTask(req)
        baseresponse.FormatResponseWithRequest(resp, err, w, r)
    }
}

Enter httpx.Parse() , mainly analyze the following pieces:

https://github.com/zeromicro/go-zero/blob/master/rest/httpx/requests.go#L32:6
  1. Parse path
  2. Parse the form
  3. Parse the http header
  4. Parse json

The function parameter check in Parse() is as follows:

https://go-zero.dev/cn/api-grammar.html in tag modifier

Tips

To learn the source code, it is recommended to fork. You can deepen your understanding when you come out and read and write comments and experiences. You can also look back when you use this feature in the future.

project address

https://github.com/zeromicro/go-zero

Welcome to use go-zero and star support us!

WeChat Exchange Group

Follow the " Practice " public account and click on the exchange group get the community group QR code.


kevinwan
931 声望3.5k 粉丝

go-zero作者