chi
est un routeur léger, idiomatique et composable pour la construction de services HTTP GO. Il est particulièrement bon pour vous aider à rédiger de grands services d'API de repos qui sont maintenus maintenables à mesure que votre projet se développe et change. chi
est construit sur le nouveau package context
introduit dans GO 1.7 pour gérer les valeurs de signalisation, d'annulation et de demande de demande dans une chaîne de gestionnaire.
L'objectif du projet a été de rechercher une conception élégante et confortable pour rédiger des serveurs API REST, écrits lors du développement du service API pressé qui alimente notre service API public, qui à son tour alimente toutes nos applications côté client.
Les principales considérations de la conception de CHI sont: la structure du projet, la maintenabilité, les gestionnaires HTTP standard (STDLIB uniquement), la productivité des développeurs et la déconstruire un grand système en de nombreuses parties. Le routeur de base github.com/go-chi/chi
est assez petit (moins de 1000 loc), mais nous avons également inclus des sous-packages utiles / facultatifs: middleware, rendu et docgen. Nous espérons que vous l'apprécierez aussi!
go get -u github.com/go-chi/chi/v5
net/http
context
, fournissant un chaînage de valeur, des annulations et des délais d'attentedocgen
Généra la documentation de routage de votre source à JSON ou MarkdownVoir _Exemples / pour une variété d'exemples.
Aussi facile que:
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 )
}
Aperçu du repos:
Voici un petit aperçu de ce à quoi ressemble le routage avec Chi. Jetez également un œil aux documents de routage générés dans JSON (Routes.json) et dans Markdown (Routes.md).
Je recommande fortement de lire la source des exemples énumérés ci-dessus, ils vous montreront toutes les fonctionnalités de Chi et serviront de bonne forme de documentation.
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 )
})
}
Le routeur de Chi est basé sur une sorte de Trie de Patricia Radix. Le routeur est entièrement compatible avec net/http
.
Construit sur le dessus de l'arbre est l'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
}
Chaque méthode de routage accepte un pattern
d'URL et une chaîne de handlers
. Le modèle d'URL prend en charge les paramètres nommés (c.-à-d. /users/{userID}
) et les wildcards (c.-. /admin/*
). Les paramètres d'URL peuvent être récupérés au moment de l'exécution en appelant chi.URLParam(r, "userID")
pour les paramètres nommés et chi.URLParam(r, "*")
pour un paramètre Wildcard.
Les Middlewares de Chi ne sont que des gestionnaires de middleware STDLIB Net / HTTP. Il n'y a rien de spécial à leur sujet, ce qui signifie que le routeur et tous les outils sont conçus pour être compatibles et amicaux avec tous les middleware de la communauté. Cela offre une bien meilleure extensibilité et réutilisation des forfaits et est au cœur du but de Chi.
Voici un exemple de middleware net / http standard où nous attribuons une clé de contexte "user"
la valeur de "123"
. Ce middleware définit un identifiant utilisateur hypothétique sur le contexte de la demande et appelle le gestionnaire suivant de la chaîne.
// 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 ))
})
}
CHI utilise des gestionnaires de demande Net / HTTP standard. Ce petit extrait est un exemple de func http.handler qui lit un identifiant utilisateur à partir du contexte de la demande - hypothétiquement, identifiant l'utilisateur envoyant une demande authentifiée, validée + définie par un gestionnaire de middleware précédent.
// 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 )))
}
Le routeur de Chi analyse et stocke les paramètres d'URL directement sur le contexte de la demande. Voici un exemple de la façon d'accéder aux paramètres d'URL dans vos gestionnaires Net / HTTP. Et bien sûr, les Middlewares peuvent accéder aux mêmes informations.
// 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 )))
}
CHI est équipé d'un package middleware
en option, fournissant une suite de middlewares net/http
standard. Veuillez noter que tout middleware de l'écosystème qui est également compatible avec net/http
peut être utilisé avec MUX de Chi.
CHI / MIDGEWARE HANDER | description |
---|---|
Permettre la conduite | Applique une liste blanche des en-têtes de codage de contenu de demande |
Autorcentype | Liste blanche explicite des types de contenu de demande acceptée |
Aauth de base | Authentification HTTP de base |
Compresse | Compression GZIP pour les clients qui acceptent les réponses compressées |
ContentCharset | Assurez-vous des en-têtes de demande de type de contenu |
Chemin de nettoyage | Nettoyer les doubles objets à la demande de demande |
Gethead | Racheter automatiquement les demandes de tête non définies pour obtenir des gestionnaires |
Pulsation | Surveillance du point de terminaison pour vérifier l'impulsion des serveurs |
Bûcheron | Enregistre le début et la fin de chaque demande avec le temps de traitement écoulé |
Nocache | Définit les en-têtes de réponse pour empêcher les clients de mettre en cache |
Profileur | Attachez facilement Net / HTTP / PPROF à vos routeurs |
Realip | Définit un Remoteaddr de Http.Request sur X-Real-IP ou X-Forwarded-For |
Rétablissement | Absorber gracieusement les paniques et imprime la trace de pile |
DemandeID | Injecte un ID de demande dans le contexte de chaque demande |
Redirection | Rediriger les barres obliques sur les chemins de routage |
Tête de route | Gestion de l'itinéraire pour les en-têtes de demande |
Chef de file | Middleware à main courte pour définir une clé / valeur d'en-tête de réponse |
Laveur | Strip trébuchent sur les chemins de routage |
Coucher de soleil | Sunset Set Deprécation / Sunset Header to Response |
Étrangler | Met un plafond sur le nombre de demandes simultanées |
Temps mort | Signaux au contexte de la demande lorsque la date limite de délai est atteint |
Urlformat | Analyser l'extension de l'URL et le mettre sur demande |
Retenir | Middleware à main courte pour définir une clé / valeur sur le contexte de la demande |
Veuillez consulter https://github.com/go-chi pour des packages supplémentaires.
emballer | description |
---|---|
cors | Partage de ressources d'origine inter-originaux (CORS) |
Docgen | Imprimer les routes Chi.router au moment de l'exécution |
jwtauth | Authentification JWT |
hostrouter | Routage de demande de domaine / hôte |
httplog | Logotage de la demande HTTP structurée petite mais puissante |
httprate | Limiteur de taux de demande HTTP |
httptracer | Bibliothèque de traçage des performances de demande HTTP |
httpvcr | Écrire des tests déterministes pour les sources externes |
débandade | HTTP demande de coalescer |
context
est un minuscule PKG qui fournit une interface simple pour signaler le contexte à travers les piles d'appels et les goroutines. Il a été écrit à l'origine par Sameer Ajmani et est disponible dans STDLIB depuis Go1.7.
En savoir plus sur https://blog.golang.org/context
et..
The Benchmark Suite: https://github.com/pkieltyka/go-http-routing-benchmark
Résultats au 29 novembre 2020 avec GO 1.15.5 sur 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
Comparaison avec les autres routeurs: https://gist.github.com/pkieltyka/123032f12052520aaccab752bd3e78cc
Remarque: Les allocs dans Context()
benchmark ci-dessus sont des appels à la méthode http.Request WithContext(context.Context)
objet. C'est ainsi que la définition du contexte sur une demande dans GO fonctionne.
Nous serons plus qu'heureux de voir vos contributions!
Chi est juste un routeur HTTP qui vous permet de décomposer la manipulation de la demande dans de nombreuses couches plus petites. De nombreuses entreprises utilisent Chi pour rédiger des services de repos pour leurs API publiques. Mais, REST n'est qu'une convention pour gérer l'état via HTTP, et il y a beaucoup d'autres pièces nécessaires pour rédiger un système client-serveur complet ou un réseau de microservices.
En regardant au-delà du repos, je recommande également des œuvres plus récentes dans le domaine:
Copyright (c) 2015-présent Peter Kieltyka
Licencié sous licence MIT