Go 1.22 e o novo router HTTP
Igor Melo
Posted on February 7, 2024
Introdução
O http.ServeMux
do Go ganhou novas features muito aguardadas pelos desenvolvedores, e como sempre, essas features são retrocompatíveis.
Em resumo, as features são:
- Match com base no método HTTP
http.Handle("GET /users", ...)
- Variavéis no path da requisição
http.Handle("GET /users/{id}", ...)
- Match exato de paths terminados em barra
// match para qualquer path iniciado com /static/
http.Handle("GET /static/", ...)
// match somente GET /static/
http.Handle("GET /static/{$}", ...)
Essas mudanças vão reduzir bastante a necessidade de utilizar bibliotecas de routers, e como vai para a stdlib, vai ter a garantia de compatibilidade do Go 1.
1. Como funciona o http.ServeMux
O ServeMux
tem um comportamento diferente da maioria dos routers.
Caminhos terminados em barra são como pastas
http.Handle("/assets/", ...)
Esse handler processa qualquer requisição com prefixo /assets/
, como:
GET /assets/
GET /assets/img/img.png
DELETE /assets/abcd
O match é feito com o path exato se não for terminado em barra
http.Handle("/", ...)
http.Handle("/assets", ...)
Nesse caso o segundo pattern não termina em barra, então só requisições para exatamente /assets
vão ser processadas por esse handler, e qualquer outra será processada pelo primeiro handler.
Obs.: O caminho /
dá match em qualquer requisição que não dê match em outro handler, então ele é geralmente usado para a página raiz e página de not found.
O match é feito com o path mais similar
Se você tiver:
http.Handle("/users/", ...)
http.Handle("/users/123", ...)
http.Handle("/users/books/", ...)
- Uma requisição para
/users/
vai cair no primeiro handler. - Uma requisição para
/users/123
vai cair no segundo handler. - Uma requisição para
/users/1234
vai cair no primeiro handler. - Uma requisição para
/users/books/123
vai cair no terceiro handler. - Uma requisição para
/users/a/b/c/d
também cai no primeiro handler
2. Entendendo o match com base no método HTTP
O comportamento das funções Handle
e HandleFunc
vai se manter igual para códigos existentes por conta da retrocompatibilidade da linguagem, então se você não especificar um método HTTP, seu handler vai continuar dando match em qualquer método.
Obs.: Um handler para o método GET vai também bater para requisições do método HEAD.
// GET /users
// HEAD /users
http.HandleFunc("GET /users", ...)
// somente DELETE /users
http.HandleFunc("DELETE /users", ...)
3. Utilizando variáveis de path
Podemos capturar o valor de uma variável de path usando o PathValue
.
http.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
...
})
4. Utilizando matches exatos
Ao utilizar o {$}
indicamos que um handler terminado em barra deve somente bater com aquele path, e não com qualquer path com aquele prefixo.
// redirecionar um request de / para /home
http.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/home")
})
// qualquer outro path que não de match em outro handler vai dar um not found
http.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
http.NotFound(w, r)
})
Conclusão
Apesar de simples, essa foi uma mudança bem importante na stdlib do Go, tendo em vista que é uma linguagem muito utilizada para desenvolver servidores Web.
Mas é claro que essas foram só algumas das muitas novidades do Go 1.22 e pretendo falar de outras que foram bem expressivas, como no for
loop, pacote rand
, e outros em próximos artigos.
Posted on February 7, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.