chi
é um roteador leve, idiomático e composto para a construção de serviços HTTP GO. É especialmente bom em ajudá -lo a escrever grandes serviços de API de REST que são mantidos mantidos à medida que seu projeto cresce e muda. chi
é construído no novo pacote context
introduzido no GO 1.7 para lidar com os valores de sinalização, cancelamento e escopo de solicitação em uma cadeia de manipuladores.
O foco do projeto foi procurar um design elegante e confortável para escrever servidores de API REST, escritos durante o desenvolvimento do Serviço de API Pressly que alimenta nosso serviço público de API, que por sua vez alimenta todos os nossos aplicativos do lado do cliente.
As principais considerações do design do CHI são: estrutura do projeto, manutenção, manipuladores HTTP padrão (somente STDLIB), produtividade do desenvolvedor e desconstruir um grande sistema em muitas pequenas partes. O roteador principal github.com/go-chi/chi
é bastante pequeno (menos de 1000 loc), mas também incluímos algumas subpackagens úteis/opcionais: middleware, renderização e docgen. Esperamos que você goste também!
go get -u github.com/go-chi/chi/v5
net/http
context
, fornecendo encadeamento de valor, cancelamentos e tempo limitedocgen
Geralates Routing Documentation de sua fonte para JSON ou MarkdownConsulte _Examples/ para uma variedade de exemplos.
Tão fácil quanto:
package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main () {
r := chi . NewRouter ()
r . Use ( middleware . Logger )
r . Get ( "/" , func ( w http. ResponseWriter , r * http. Request ) {
w . Write ([] byte ( "welcome" ))
})
http . ListenAndServe ( ":3000" , r )
}
PREVISÃO DE REST:
Aqui está uma pequena prévia de como é o roteamento com o chi. Dê uma olhada nos documentos de roteamento gerado em json (rotas.json) e em markdown (rotas.md).
Eu recomendo ler a fonte dos exemplos listados acima, eles mostrarão todos os recursos do CHI e servirão como uma boa forma de documentação.
import (
//...
"context"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main () {
r := chi . NewRouter ()
// A good base middleware stack
r . Use ( middleware . RequestID )
r . Use ( middleware . RealIP )
r . Use ( middleware . Logger )
r . Use ( middleware . Recoverer )
// Set a timeout value on the request context (ctx), that will signal
// through ctx.Done() that the request has timed out and further
// processing should be stopped.
r . Use ( middleware . Timeout ( 60 * time . Second ))
r . Get ( "/" , func ( w http. ResponseWriter , r * http. Request ) {
w . Write ([] byte ( "hi" ))
})
// RESTy routes for "articles" resource
r . Route ( "/articles" , func ( r chi. Router ) {
r . With ( paginate ). Get ( "/" , listArticles ) // GET /articles
r . With ( paginate ). Get ( "/{month}-{day}-{year}" , listArticlesByDate ) // GET /articles/01-16-2017
r . Post ( "/" , createArticle ) // POST /articles
r . Get ( "/search" , searchArticles ) // GET /articles/search
// Regexp url parameters:
r . Get ( "/{articleSlug:[a-z-]+}" , getArticleBySlug ) // GET /articles/home-is-toronto
// Subrouters:
r . Route ( "/{articleID}" , func ( r chi. Router ) {
r . Use ( ArticleCtx )
r . Get ( "/" , getArticle ) // GET /articles/123
r . Put ( "/" , updateArticle ) // PUT /articles/123
r . Delete ( "/" , deleteArticle ) // DELETE /articles/123
})
})
// Mount the admin sub-router
r . Mount ( "/admin" , adminRouter ())
http . ListenAndServe ( ":3333" , r )
}
func ArticleCtx ( next http. Handler ) http. Handler {
return http . HandlerFunc ( func ( w http. ResponseWriter , r * http. Request ) {
articleID := chi . URLParam ( r , "articleID" )
article , err := dbGetArticle ( articleID )
if err != nil {
http . Error ( w , http . StatusText ( 404 ), 404 )
return
}
ctx := context . WithValue ( r . Context (), "article" , article )
next . ServeHTTP ( w , r . WithContext ( ctx ))
})
}
func getArticle ( w http. ResponseWriter , r * http. Request ) {
ctx := r . Context ()
article , ok := ctx . Value ( "article" ).( * Article )
if ! ok {
http . Error ( w , http . StatusText ( 422 ), 422 )
return
}
w . Write ([] byte ( fmt . Sprintf ( "title:%s" , article . Title )))
}
// A completely separate router for administrator routes
func adminRouter () http. Handler {
r := chi . NewRouter ()
r . Use ( AdminOnly )
r . Get ( "/" , adminIndex )
r . Get ( "/accounts" , adminListAccounts )
return r
}
func AdminOnly ( next http. Handler ) http. Handler {
return http . HandlerFunc ( func ( w http. ResponseWriter , r * http. Request ) {
ctx := r . Context ()
perm , ok := ctx . Value ( "acl.permission" ).( YourPermissionType )
if ! ok || ! perm . IsAdmin () {
http . Error ( w , http . StatusText ( 403 ), 403 )
return
}
next . ServeHTTP ( w , r )
})
}
O roteador de Chi é baseado em uma espécie de Trie da Patricia Radix. O roteador é totalmente compatível com net/http
.
Construído em cima da árvore está a interface Router
:
// Router consisting of the core routing methods used by chi's Mux,
// using only the standard net/http.
type Router interface {
http. Handler
Routes
// Use appends one or more middlewares onto the Router stack.
Use ( middlewares ... func (http. Handler ) http. Handler )
// With adds inline middlewares for an endpoint handler.
With ( middlewares ... func (http. Handler ) http. Handler ) Router
// Group adds a new inline-Router along the current routing
// path, with a fresh middleware stack for the inline-Router.
Group ( fn func ( r Router )) Router
// Route mounts a sub-Router along a `pattern`` string.
Route ( pattern string , fn func ( r Router )) Router
// Mount attaches another http.Handler along ./pattern/*
Mount ( pattern string , h http. Handler )
// Handle and HandleFunc adds routes for `pattern` that matches
// all HTTP methods.
Handle ( pattern string , h http. Handler )
HandleFunc ( pattern string , h http. HandlerFunc )
// Method and MethodFunc adds routes for `pattern` that matches
// the `method` HTTP method.
Method ( method , pattern string , h http. Handler )
MethodFunc ( method , pattern string , h http. HandlerFunc )
// HTTP-method routing along `pattern`
Connect ( pattern string , h http. HandlerFunc )
Delete ( pattern string , h http. HandlerFunc )
Get ( pattern string , h http. HandlerFunc )
Head ( pattern string , h http. HandlerFunc )
Options ( pattern string , h http. HandlerFunc )
Patch ( pattern string , h http. HandlerFunc )
Post ( pattern string , h http. HandlerFunc )
Put ( pattern string , h http. HandlerFunc )
Trace ( pattern string , h http. HandlerFunc )
// NotFound defines a handler to respond whenever a route could
// not be found.
NotFound ( h http. HandlerFunc )
// MethodNotAllowed defines a handler to respond whenever a method is
// not allowed.
MethodNotAllowed ( h http. HandlerFunc )
}
// Routes interface adds two methods for router traversal, which is also
// used by the github.com/go-chi/docgen package to generate documentation for Routers.
type Routes interface {
// Routes returns the routing tree in an easily traversable structure.
Routes () [] Route
// Middlewares returns the list of middlewares in use by the router.
Middlewares () Middlewares
// Match searches the routing tree for a handler that matches
// the method/path - similar to routing a http request, but without
// executing the handler thereafter.
Match ( rctx * Context , method , path string ) bool
}
Cada método de roteamento aceita um pattern
de URL e uma cadeia de handlers
. O padrão URL suporta params nomeados (ou seja, /users/{userID}
) e WildCards (ou seja, /admin/*
). Os parâmetros da URL podem ser buscados no tempo de execução ligando para chi.URLParam(r, "userID")
para parâmetros nomeados e chi.URLParam(r, "*")
para um parâmetro curinga.
O Middlewares da Chi são apenas manipuladores de middleware de rede/http de STDLIB. Não há nada de especial neles, o que significa que o roteador e todas as ferramentas foram projetadas para serem compatíveis e amigáveis com qualquer middleware da comunidade. Isso oferece extensibilidade muito melhor e reutilização de pacotes e está no centro do propósito de Chi.
Aqui está um exemplo de um middleware NET/HTTP padrão, onde atribuímos uma chave de contexto "user"
o valor de "123"
. Este middleware define um identificador hipotético do usuário no contexto de solicitação e chama o próximo manipulador na cadeia.
// HTTP middleware setting a value on the request context
func MyMiddleware ( next http. Handler ) http. Handler {
return http . HandlerFunc ( func ( w http. ResponseWriter , r * http. Request ) {
// create new context from `r` request context, and assign key `"user"`
// to value of `"123"`
ctx := context . WithValue ( r . Context (), "user" , "123" )
// call the next handler in the chain, passing the response writer and
// the updated request object with the new context value.
//
// note: context.Context values are nested, so any previously set
// values will be accessible as well, and the new `"user"` key
// will be accessible from this point forward.
next . ServeHTTP ( w , r . WithContext ( ctx ))
})
}
O CHI usa manipuladores de solicitação de rede/http padrão padrão. Este pequeno snippet é um exemplo de uma função http.handler que lê um identificador de usuário do contexto de solicitação - hipoteticamente, identificando o usuário enviando uma solicitação autenticada, validada+definido por um manipulador de middleware anterior.
// HTTP handler accessing data from the request context.
func MyRequestHandler ( w http. ResponseWriter , r * http. Request ) {
// here we read from the request context and fetch out `"user"` key set in
// the MyMiddleware example above.
user := r . Context (). Value ( "user" ).( string )
// respond to the client
w . Write ([] byte ( fmt . Sprintf ( "hi %s" , user )))
}
O roteador de Chi passa e armazena parâmetros de URL diretamente no contexto da solicitação. Aqui está um exemplo de como acessar os parâmetros de URL em seus manipuladores de rede/http. E, é claro, os Middlewares são capazes de acessar as mesmas informações.
// HTTP handler accessing the url routing parameters.
func MyRequestHandler ( w http. ResponseWriter , r * http. Request ) {
// fetch the url parameter `"userID"` from the request of a matching
// routing pattern. An example routing pattern could be: /users/{userID}
userID := chi . URLParam ( r , "userID" )
// fetch `"key"` from the request context
ctx := r . Context ()
key := ctx . Value ( "key" ).( string )
// respond to the client
w . Write ([] byte ( fmt . Sprintf ( "hi %v, %v" , userID , key )))
}
O CHI vem equipado com um pacote middleware
opcional, fornecendo um conjunto de middlewares net/http
padrão. Observe que qualquer middleware no ecossistema que também é compatível com net/http
pode ser usado com o MUX do CHI.
Manipulador de Chi/Middleware | descrição |
---|---|
Permitir quecontente | Aplica uma lista de permissões de cabeçalhos de codificação de conteúdo de solicitação |
PermitirContentType | Lista de permissões explícitas dos tipos de conteúdo de solicitação aceita |
BASICAUTH | Autenticação HTTP básica |
Compressa | Compressão GZIP para clientes que aceitam respostas compactadas |
Contentcharset | Certifique-se de que os cabeçalhos de solicitação do tipo de conteúdo |
Limpeza | Limpe as barras duplas do caminho de solicitação |
Gethead | Rotear automaticamente solicitações de cabeça indefinida para obter manipuladores |
Batimento cardíaco | Monitorando o terminal para verificar o pulso dos servidores |
Logger | Registra o início e o fim de cada solicitação com o tempo de processamento decorrido |
Nocache | Define cabeçalhos de resposta para impedir que os clientes em cache |
Profiler | Anexe facilmente net/http/pprof aos seus roteadores |
Realip | Define um remoteaddr de http.request para x-real-ip ou x-forwarded for |
Recuperador | Absorver graciosamente o pânico e imprime o rastreamento da pilha |
RequestId | Injeta um ID de solicitação no contexto de cada solicitação |
RedirectSlashes | Redirecionar cortes nos caminhos de roteamento |
RouteHeaders | Manuseio de rota para cabeçalhos de solicitação |
Setheader | Middleware curto para definir uma chave/valor de cabeçalho de resposta |
Strapslashes | Tira corta os caminhos de roteamento |
Pôr do sol | Cabeçalho de depreciação/pôr do sol do pôr do sol para resposta |
Acelerar | Coloca um teto no número de solicitações simultâneas |
Tempo esgotado | Sinaliza para o contexto de solicitação quando o prazo de limite é alcançado |
Urlformat | Excesso de análise do URL e coloque -o a pedido de contexto de solicitação |
Com valor | Middleware curto para definir uma chave/valor no contexto de solicitação |
Consulte https://github.com/go-chi para obter pacotes adicionais.
pacote | descrição |
---|---|
cors | Compartilhamento de Recursos Cross-Origin (CORS) |
docgen | Imprima rotas Chi.Router em tempo de execução |
Jwtauth | Autenticação JWT |
Hostrouter | Roteamento de solicitação baseado em domínio/host |
httpLog | Loging HTTP estruturado pequeno, mas poderoso |
httprate | Limitador de taxa de solicitação HTTP |
httptracer | Biblioteca de rastreamento de desempenho de solicitação HTTP |
httpvcr | Escreva testes determinísticos para fontes externas |
debandada | Solicitação HTTP Coalescer |
context
é um pequeno PKG que fornece interface simples para sinalizar o contexto entre pilhas de chamadas e goroutines. Foi originalmente escrito por Sameer Ajmani e está disponível no stdlib desde o GO1.7.
Saiba mais em https://blog.golang.org/context
e..
The Benchmark Suite: https://github.com/pkieltyka/go-http-routing-benchmark
Resultados a partir de 29 de novembro de 2020 com GO 1.15.5 no Linux AMD 3950X
BenchmarkChi_Param 3075895 384 ns/op 400 B/op 2 allocs/op
BenchmarkChi_Param5 2116603 566 ns/op 400 B/op 2 allocs/op
BenchmarkChi_Param20 964117 1227 ns/op 400 B/op 2 allocs/op
BenchmarkChi_ParamWrite 2863413 420 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GithubStatic 3045488 395 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GithubParam 2204115 540 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GithubAll 10000 113811 ns/op 81203 B/op 406 allocs/op
BenchmarkChi_GPlusStatic 3337485 359 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GPlusParam 2825853 423 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GPlus2Params 2471697 483 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GPlusAll 194220 5950 ns/op 5200 B/op 26 allocs/op
BenchmarkChi_ParseStatic 3365324 356 ns/op 400 B/op 2 allocs/op
BenchmarkChi_ParseParam 2976614 404 ns/op 400 B/op 2 allocs/op
BenchmarkChi_Parse2Params 2638084 439 ns/op 400 B/op 2 allocs/op
BenchmarkChi_ParseAll 109567 11295 ns/op 10400 B/op 52 allocs/op
BenchmarkChi_StaticAll 16846 71308 ns/op 62802 B/op 314 allocs/op
Comparação com outros roteadores: https://gist.github.com/pkieltyka/123032f12052520aaccab752bd3e78cc
NOTA: Os aloces na referência acima são do método de chamadas para o método Http.Request WithContext(context.Context)
que clone o http.request, define o Context()
na solicitação duplicada (alocada) e retorna a nova solicitação objeto. É assim que a definição de contexto em uma solicitação no Go funciona.
Ficaremos mais do que felizes em ver suas contribuições!
O CHI é apenas um roteador HTTP que permite decompor o manuseio de solicitações em muitas camadas menores. Muitas empresas usam o CHI para escrever serviços de repouso para suas APIs públicas. Mas o REST é apenas uma convenção para gerenciar o estado via HTTP, e há muitas outras peças necessárias para escrever um sistema ou rede de microsserviços clientes e servidores completos.
Olhando além do descanso, eu também recomendo alguns trabalhos mais recentes no campo:
Copyright (c) 2015-presente Peter Kieltyka
Licenciado sob licença do MIT