Skip to main content

Middleware declaration

Overview

In go-zero, we declared HTTP service via api language, and then generated HTTP service code via goctl, after our systematic introduction to API norm.

Middleware is a very common need in HTTP development, such as that we need to authenticate requests or log requests that are very common.

Middleware declaration

Assuming that we have a user service, we need to post user-agent information into the context message, and then process it in the logical layer according to user-agent, we can declare intermediates through api language, in api languages, we can declare intermediates by midsleware keywords and the medieval declaration format is below:

syntax = "v1"

type UserInfoRequest {
Id int64 `path:"id"`
}
type UserInfoResponse {
Id int64 `json:"id"`
Name string `json:"name"`
Age int32 `json:"age"`
}

@server(
// Middleware is declared through the middleware keyword, and multiple middleware are separated by English commas, such asUserAgentMiddleware,LogMiddleware
middleware: UserAgentMiddleware
)
service user {
@handler userinfo
get /user/info/:id (UserInfoRequest) returns (UserInfoResponse)
}

In the example above, we have stated a midpoint UserAgentMidleareand then declare the middle of a keyword in @server by middileware Let's look at the generated intermediate code:

Directory Structure

.
├── etc
│   └── user.yaml
├── internal
│   ├── config
│   │   └── config.go
│   ├── handler
│   │   ├── routes.go
│   │   └── userinfohandler.go
│   ├── logic
│   │   └── userinfologic.go
│   ├── middleware # middleware directory
│   │   └── useragentmiddleware.go
│   ├── svc
│   │   └── servicecontext.go
│   └── types
│   └── types.go
├── user.api
└── user.go

8 directories, 10 files

Middleware code (no fill logic)

package middleware

import "net/http"

type UserAgentMiddleware struct {
}

func NewUserAgentMiddleware() *UserAgentMiddleware {
return &UserAgentMiddleware{}
}

func (m *UserAgentMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// TODO generate middleware implement function, delete after code implementation

// Passthrough to next handler if need
next(w, r)
}
}

You can see that the middleware code is automatically generated via goctl, that the intermediate code is a structure in which there is a Handle method, which is the core method of the medium, which receives a parameter of type http.HandlerFunc and returns a parameter of type http.HandlerFunc which is used to process requests and then pass the request to the next intermediate or handler.

You can process requests in Handle methods such as authentication, log records, and then pass the request to the next intermediate or handler.

As the above requirement example, we can store the User-Agent information in the header into the context in the middleware, and the middleware is implemented as follows:

package middleware

import (
"context"
"net/http"
)

type UserAgentMiddleware struct {
}

func NewUserAgentMiddleware() *UserAgentMiddleware {
return &UserAgentMiddleware{}
}

func (m *UserAgentMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
val := r.Header.Get("User-Agent")
reqCtx := r.Context()
ctx := context.WithValue(reqCtx, "User-Agent", val)
newReq := r.WithContext(ctx)
next(w, newReq)
}
}