chi
ist ein leichter, idiomatischer und komponierbarer Router für den Bau von GO -HTTP -Diensten. Es ist besonders gut darin, Ihnen dabei zu helfen, große REST -API -Dienste zu schreiben, die beim Wachstum Ihres Projekts aufrechterhalten werden. chi
basiert auf dem neuen context
, das in Go 1.7 eingeführt wurde, um Signal-, Stornierungs- und Anforderungswerte in einer Handlerkette zu verarbeiten.
Der Schwerpunkt des Projekts lag darauf, ein elegantes und komfortables Design für das Schreiben von REST-API-Servern aufzusuchen, die während der Entwicklung des Pressly-API-Dienstes geschrieben wurden, der unseren öffentlichen API-Dienst anführt, der wiederum alle unsere Kunden auf dem Kunden beantragt.
Die wichtigsten Überlegungen zum Design von CHI sind: Projektstruktur, Wartbarkeit, Standard-HTTP-Handler (nur STDLIB), Entwicklerproduktivität und Dekonstruktion eines großen Systems in viele kleine Teile. Der Kernrouter github.com/go-chi/chi
ist ziemlich klein (weniger als 1000 LOC), aber wir haben auch einige nützliche/optionale Unterpackungen enthalten: Middleware, Render und Docgen. Wir hoffen, es gefällt Ihnen auch!
go get -u github.com/go-chi/chi/v5
net/http
kompatibel istcontext
, bereitgestellt Wertscharen, Stornierungen und Zeitüberschreitungendocgen
automatisch generiert Routing -Dokumentation von Ihrer Quelle zu JSON oder MarkdownSiehe _Examples/ für eine Vielzahl von Beispielen.
So einfach wie:
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 )
}
REST -Vorschau:
Hier ist eine kleine Vorschau auf das Routing mit Chi. Schauen Sie sich auch die generierten Routing -Dokumente in JSON (Routes.json) und in Markdown (Routes.md) an.
Ich empfehle dringend, die Quelle der oben aufgeführten Beispiele zu lesen. Sie zeigen Ihnen alle Funktionen von Chi und dienen als gute Form der Dokumentation.
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 )
})
}
Chis Router basiert auf einer Art Patricia Radix -Trie. Der Router ist mit net/http
vollständig kompatibel.
Auf dem Baum befindet sich die Router
-Schnittstelle:
// 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
}
Jede Routing -Methode akzeptiert ein URL pattern
und eine Kette von handlers
. Das URL -Muster unterstützt benannte Params (dh /users/{userID}
) und Wildcards (dh /admin/*
). URL -Parameter können zur Laufzeit abgerufen werden, indem chi.URLParam(r, "userID")
für benannte Parameter und chi.URLParam(r, "*")
für einen Wildcard -Parameter aufgerufen werden.
Chis Middlewares sind nur Stdlib Net/HTTP Middleware -Handler. Sie haben nichts Besonderes, was bedeutet, dass der Router und das gesamte Werkzeug kompatibel und freundlich mit jeder Middleware in der Community sind. Dies bietet eine viel bessere Erweiterbarkeit und Wiederverwendung von Paketen und steht im Herzen von Chis Zweck.
Hier ist ein Beispiel für ein Standard -Net/HTTP -Middleware, in dem wir einen Kontextschlüssel "user"
den Wert von "123"
. Diese Middleware legt eine hypothetische Benutzerkennung im Anforderungskontext fest und ruft den nächsten Handler in der Kette auf.
// 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 verwendet Standard -Net/HTTP -Anforderungshandler. Dieser kleine Ausschnitt ist ein Beispiel für einen HTTP.Handler -Func, der eine Benutzerkennung aus dem Anforderungskontext liest - hypothetisch, indem der Benutzer eine authentifizierte Anforderung identifiziert, die von einem vorherigen Middleware -Handler validiert wurde.
// 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 )))
}
Der Router von Chi pariert und speichert URL -Parameter direkt in den Anforderungskontext. Hier ist ein Beispiel für den Zugriff auf URL -Parameter in Ihren Net/HTTP -Handlern. Und natürlich können Middlewares auf die gleichen Informationen zugreifen.
// 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 ist mit einem optionalen middleware
-Paket ausgestattet und bietet eine Reihe von Standard net/http
-Middlewares. Bitte beachten Sie, dass jede Middleware im Ökosystem, das auch mit net/http
kompatibel ist, mit Chi's MUX verwendet werden kann.
Chi/Middleware -Handler | Beschreibung |
---|---|
Zulassungskopie | Erzwingt einen Whitelist von Anforderungs-Inhaltskodier-Headern |
ALLECONTTYPE | Explizite Whitelist der anerkannten Anforderungsinhaltstypen |
BasicAuth | Grundlegende HTTP -Authentifizierung |
Kompresse | GZIP -Komprimierung für Clients, die komprimierte Antworten akzeptieren |
ContentCharSet | Stellen Sie Charset für Inhaltsanforderungs-Header sicher |
Reinigungspath | Reinigen Sie doppelte Schrägstriche vom Anfragepfad |
Gethead | Leiten Sie automatisch undefinierte Kopfanfragen, um Handler zu erhalten |
Herzschlag | Überwachung des Endpunkts zum Überprüfen des Serverpuls |
Logger | Melden Sie sich mit der verstrichenen Verarbeitungszeit den Start und Ende jeder Anfrage an |
Nocache | Legt Reaktionsüberschriften fest, um Kunden am zwischengespeichertem Kunden zu verhindern |
Profiler | Befestigen Sie Ihre Router einfach Net/HTTP/PPROF |
Realip | Setzt eine remoteaddr von http.request entweder auf X-real-ip oder x-forwarded-for-for |
Wiederhersteller | Absorpt Panik und druckt die Stapelspur anmutig auf |
Anfrage | Injiziert eine Anforderungs -ID in den Kontext jeder Anfrage |
Umleitungsläzungen | Schrägungen auf Routing -Pfaden umleiten |
Routenführer | Routenhandhabung für Anfragenüberschriften |
Setheader | Kurzhand-Middleware, um einen Antwort-Header-Schlüssel/-wert festzulegen |
Stripslashes | Streifen Sie Schrägstriche auf Routing -Pfaden ab |
Sonnenuntergang | Sonnenuntergangs -Abschalt-/Sonnenuntergangs -Header zur Reaktion |
Gaspedal | Legt eine Decke auf die Anzahl der gleichzeitigen Anfragen |
Time-out | Signale auf den Anforderungskontext, wenn die Zeitüberschreitungsfrist erreicht ist |
URLFORMAT | Nehmen Sie die Erweiterung von der URL an und setzen Sie sie in Anforderungskontext ein |
WithValue | Kurzhand-Middleware, um einen Schlüssel/Wert im Anforderungskontext festzulegen |
Weitere Pakete finden Sie unter https://github.com/go-chi.
Paket | Beschreibung |
---|---|
CORS | Cross-Origin-Ressourcenfreigabe (CORS) |
DOCGEN | Drucken Sie die Routen von Chi.router zur Laufzeit aus |
Jwtauth | JWT -Authentifizierung |
Hostrouter | Domain/Host -basierte Anforderungsrouting |
httplog | Kleine, aber leistungsstrukturierte strukturierte HTTP -Anfrageprotokollierung |
httpreat | HTTP -Anforderungsratenbegrenzer |
httptracer | HTTP -Anfrage -Leistungsverfolgung Bibliothek |
httpvcr | Schreiben Sie deterministische Tests für externe Quellen |
Ansturm | HTTP -Anfrage Coalescer |
context
ist eine winzige PKG, die eine einfache Schnittstelle zum Signalkontext über Anrufstapel und Goroutinen bietet. Es wurde ursprünglich von Sameer Ajmani geschrieben und ist seit Go1.7 in STDLIB erhältlich.
Erfahren Sie mehr unter https://blog.golang.org/context
Und..
Die Benchmark-Suite: https://github.com/pkieltyka/go-http-routing-fenchmark
Ergebnisse ab dem 29. November 2020 mit GO 1.15.5 auf 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
Vergleich mit anderen Routern: https://gist.github.com/pkieltyka/123032f12052520aaccab752bd3e78cc
Hinweis: Die Allocs im obigen Benchmark stammen aus den Aufrufen zu http.requests WithContext(context.Context)
, die die http.request kloniert, den Context()
auf der doppelten (Alloc'd) -Anfrage festgelegt und die neue Anfrage zurückgibt Objekt. So funktioniert das Einstellen von Kontext auf eine Anfrage in Go.
Wir freuen uns mehr als gerne Ihre Beiträge!
Chi ist nur ein HTTP -Router, mit dem Sie die Anfrage in viele kleinere Schichten zerlegen können. Viele Unternehmen nutzen Chi, um Rastdienste für ihre öffentlichen APIs zu schreiben. REST ist jedoch nur eine Konvention für die Verwaltung des Status über HTTP, und es sind viele andere Teile erforderlich, um ein vollständiges Client-Server-System oder ein Netzwerk von Microservices zu schreiben.
Wenn ich über die Pause hinausgehe, empfehle ich auch einige neuere Arbeiten in diesem Bereich:
Copyright (c) 2015-Präsentation Peter Kieltyka
Unter MIT -Lizenz lizenziert