đ Middlewares
đĒ Priorityâ
It's essential to understand how middlewares work. The middleware that gets called the last, has the most "power", since it can override values that have been set in previous middlewares.
If you call .Use()
anywhere, you will register a global middleware for the entire router. On the other hand, .With()
only defines a middleware for one single endpoint, being the most recent one defined.
Have a look at this example to build an understanding of the execution order.
package main
import (
"fmt"
"github.com/Gebes/there/v2"
"github.com/Gebes/there/v2/status"
"log"
)
type User struct {
Id int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Admin bool `json:"admin,omitempty"`
}
func main() {
router := there.NewRouter()
router.Use(func(request there.Request, next there.Response) there.Response {
fmt.Println("Global 1")
return there.Headers(map[string]string{"Test": "Global 1"}, next)
})
router.Use(func(request there.Request, next there.Response) there.Response {
fmt.Println("Global 2")
return there.Headers(map[string]string{"Test": "Global 2"}, next)
})
router.Get("/", Get).With(func(request there.Request, next there.Response) there.Response {
fmt.Println("Specific 1")
return there.Headers(map[string]string{"Test": "Specific 1"}, next)
}).With(func(request there.Request, next there.Response) there.Response {
fmt.Println("Specific 2")
return there.Headers(map[string]string{"Test": "Specific 2"}, next)
})
err := router.Listen(8080)
if err != nil {
log.Fatalln("Could not listen to 8080", err)
}
}
func Get(request there.Request) there.Response {
return there.Auto(status.OK, User{
Id: 5,
Name: "Chris",
Admin: true,
})
}
Output
Specific 2
Specific 1
Global 2
Global 1
and the Test
-Header gets set to Global 1
.
đī¸ Default middlewaresâ
There provides several useful middlewares out of the box.
đĨ Recovererâ
Recovers from a panic, should be the first global middleware if used
router.Use(middlewares.Recoverer)
đŠē Loggerâ
Logs every request and the body of messages with an error
The order of the middlewares matters. If you have a Gzip Middleware, you should add the Logger Middleware afterwards. Otherwise, the Logger Middleware can only read the gibberish compressed data.
âŦī¸ Gzipâ
Compressing data can be useful, to improve the response time of the API, since less networking is required.
This custom middleware simply compresses every result.
However, be careful again! If you have a generic endpoint in your project, and you also use the there.Gzip()
response as a wrapper, you will compress your data twice.
router.Use(func(request there.Request, next there.Response) there.Response {
return there.Gzip(next)
})
đŽâ CORSâ
Be careful with the CORS headers you set. If you are building an open API, you may want to expose every route for every website. However, if you use authentication, you should secure your endpoint in a better way.
router.Use(middlewares.Cors(middlewares.CorsAllowAllConfiguration()))
package main
import (
"errors"
"github.com/Gebes/there/v2"
"github.com/Gebes/there/v2/middlewares"
"github.com/Gebes/there/v2/status"
"log"
"math/rand"
)
type User struct {
Id int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Admin bool `json:"admin,omitempty"`
}
func main() {
router := there.NewRouter()
router.Use(middlewares.Recoverer)
router.Use(middlewares.Logger())
router.Use(func(request there.Request, next there.Response) there.Response {
return there.Gzip(next)
})
router.Use(middlewares.Cors(middlewares.CorsAllowAllConfiguration()))
router.Get("/", Get)
err := router.Listen(8080)
if err != nil {
log.Fatalln("Could not listen to 8080", err)
}
}
func Get(request there.Request) there.Response {
if rand.Int()%3 == 0 {
return there.Error(status.InternalServerError, errors.New("something went wrong"))
}
return there.Auto(status.OK, User{
Id: 5,
Name: "Chris",
Admin: true,
})
}