Overview of rest frameworks
To generate an API service, go Zero uses the command-line tool goctl. Its main function is as follows:
func main(a) {
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()
}
Copy the code
- Parsing configuration files
- Pass in the configuration file and initialize it
serviceContext
- Initialize the
rest server
- will
context
injectionserver
In:- Registered routing
- will
context
In startendpoint
Simultaneously inject intorouter
among
- Start the
server
Let’s explain the design principle step by step! Let’s Go!
Web framework
From everyday development experience, a good Web framework generally meets the following characteristics:
- Route matching/multiple route support
- Support for custom middleware
- Framework and business development are completely decoupled, making it easy for developers to develop quickly
- Parameter verification/matching
- Monitor, log, and indicator self-check functions
- Service self-protection (fusing/current limiting)
Go – zero rest design
Github.com/zeromicro/g…
An overview of
- Initialize the resource with context (different from gin’s context) → save it in
serviveCtx
(For resource pooling, let the resource handle itself,serviveCtx
Just entry and sharing points) - Separate router declaration files and add router groups to make code structure easier for developers
- Several built-in middleware: monitoring/fusing/authentication, etc
- Using goCTL CodeGen + Option design mode, it is convenient for developers to control the access of some middleware by themselves
The figure above describes the rest pattern for processing requests and most of the processing paths.
- The middleware built into the framework already handles most of the service self-processing logic for developers
- At the same time go to zero
business logic
Also gives developers out-of-the-box components (DQ, FX, etc.) - From the development mode to help developers only need to focus on their own
business logic
And the preparation of required resources
Let’s take a closer look at how rest gets started.
Start the process
The figure above describes the overall server startup module and general flow. The rest implementation is analyzed as follows:
- Http. server based encapsulation and transformation: Separate Engine (core web framework) from Option
- Multi – route matching adopts the radix-tree construction
- Middleware adopts onion model →
[]Middleware
- HTTP parse and match verification →
httpx.Parse()
- Metrics are collected during the request (
createMetrics()
) and monitoring buried sites (Prometheus)
Server engine assembly
Click on the larger image to view
Engine runs through the server lifecycle:
- The router carries a developer-defined path/handler, which is executed in the final router.handle()
- Registered custom middleware + framework middleware, executed in front of Router Handler Logic
Here we go: The granularity of go-Zero processing is on the route, and encapsulation and processing are performed layer by layer along the route
Routing matching
So when a request comes in, how does it 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 code:
type helloHandler struct{}
func (h *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, world!"))}func main(a) {
http.Handle("/", &helloHandler{})
http.ListenAndServe(": 12345".nil)}Copy the code
HTTP.ListenAndServe() is executed internally: server.listenAndServe ()
Let’s see how this works in REST:
The incoming handler is the router generated by router.newrouter (). The Router hosts the entire set of server handlers.
The http.Server structure is initialized to inject a handler into it:
type Server struct{... Handler Handler }func start(... , handler http.Handler, runfunc(srv *http.Server) error) (err error) {
server := &http.Server{
Addr: fmt.Sprintf("%s:%d", host, port),
Handler: handler,
}
...
return run(server)
}
Copy the code
After http.Server receives req, handler.ServeHTTP(rW, req)
So the built-in router also needs to be implementedServeHTTP
. How is the Router itself implementedServeHTTP
: Searches for the matched route and executes the Handle Logic corresponding to the route.
Analytical parameters
Parsing parameters is a basic capability that HTTP frameworks need 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
iferr := 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)
}
}
Copy the code
Enter httpx.parse () to Parse the following blocks:
Github.com/zeromicro/g…
- Parsing path
- Parsing form forms
- Parsing the HTTP header
- Parsing json
The parameter verification function in Parse() can be found in:
Go – zero. Dev/cn/API – “gramm… Tag modifier in
Tips
Learn source code recommendation fork out to see while writing comments and experience, you can deepen understanding, later use this feature can also go back to read.
The project address
Github.com/zeromicro/g…
Welcome to Go-Zero and star support us!
Wechat communication group
Pay attention to the public account of “micro-service Practice” and click on the exchange group to obtain the QR code of the community group.