chi
、GO HTTPサービスを構築するための軽量で慣用的で構成可能なルーターです。プロジェクトが成長し、変化するにつれて維持可能に保たれた大規模なREST APIサービスの作成を支援するのが特に優れています。 chi
、Go 1.7で導入された新しいcontext
パッケージの上に構築され、ハンドラーチェーン全体で信号、キャンセル、リクエストスコープの値を処理します。
このプロジェクトの焦点は、パブリックAPIサービスの開発中に記述されたREST APIサーバーを作成するためのエレガントで快適なデザインを探すことでした。
Chiの設計の重要な考慮事項は、プロジェクト構造、保守性、標準のHTTPハンドラー(STDLIBのみ)、開発者の生産性、大規模なシステムを多くの小さな部品に分解することです。コアルーターgithub.com/go-chi/chi
は非常に小さい(1000 loc未満)ですが、ミドルウェア、レンダリング、docgenの便利/オプションのサブパッケージも含まれています。あなたもそれを楽しんでいただければ幸いです!
go get -u github.com/go-chi/chi/v5
net/http
と互換性のあるエコシステムでHTTPまたはミドルウェアPKGを使用しますcontext
パッケージに基づいて構築され、値チェーン、キャンセル、タイムアウトを提供しますdocgen
ソースからJSONまたはマークダウンへのルーティングドキュメントを自動生成しますさまざまな例については、_examples/を参照してください。
簡単に同じくらい簡単です:
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 )
}
休憩プレビュー:
これは、ルーティングがChiでどのように見えるかについての少しのプレビューです。また、JSON(routes.json)とMarkdown(routes.md)の生成されたルーティングドキュメントもご覧ください。
上記の例のソースを読むことを強くお勧めします。Chiのすべての機能を示し、ドキュメントの優れた形式として機能します。
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 )
})
}
チーのルーターは、一種のパトリシアラジックストリーに基づいています。ルーターは、 net/http
と完全に互換性があります。
ツリーの上に構築されているのは、 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
}
各ルーティング方法は、URL pattern
とhandlers
のチェーンを受け入れます。 URLパターンは、名前のparams(ie。 /users/{userID}
)とワイルドカード(すなわち/admin/*
)という名前をサポートしています。 URLパラメーターは、名前付きパラメーターのchi.URLParam(r, "userID")
を呼び出し、ワイルドカードパラメーターにchi.URLParam(r, "*")
呼び出すことにより、実行時にフェッチできます。
ChiのMiddlewaresは、stdlib net/httpミドルウェアハンドラーです。それらについて特別なものは何もありません。つまり、ルーターとすべてのツールは、コミュニティの中間ウェアと互換性がありフレンドリーになるように設計されています。これにより、パッケージの拡張性と再利用がはるかに優れており、チーの目的の中心にあります。
以下は、コンテキストキー"user"
の値を"123"
の値に割り当てる標準のネット/HTTPミドルウェアの例です。このミドルウェアは、要求コンテキストで仮想ユーザー識別子を設定し、チェーンの次のハンドラーを呼び出します。
// 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は標準のNet/HTTP要求ハンドラーを使用します。この小さなスニペットは、リクエストコンテキストからユーザー識別子を読み取るhttp.handler funcの例です。仮説的に、ユーザーが以前のミドルウェアハンドラーによって検証+設定された認証された要求を送信するユーザーを識別します。
// 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 )))
}
Chiのルーターは、URLパラメーターを要求のコンテキストにまさに解析および保存します。ネット/HTTPハンドラーにURLパラメーションにアクセスする方法の例を次に示します。そしてもちろん、MiddleWaresは同じ情報にアクセスできます。
// 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には、オプションのmiddleware
パッケージが装備されており、標準のnet/http
Middlewaresのスイートを提供します。 net/http
と互換性のあるエコシステム内のミドルウェアは、ChiのMUXと一緒に使用できます。
カイ/ミドルウェアハンドラー | 説明 |
---|---|
AllowContentEncoding | リクエストコンテンツエンコードヘッダーのホワイトリストを強制します |
AllowContentType | 受け入れられたリクエストコンテンツタイプの明示的なホワイトリスト |
BasicAuth | 基本的なHTTP認証 |
圧縮 | 圧縮応答を受け入れるクライアントのGZIP圧縮 |
ContentCharset | コンテンツタイプのリクエストヘッダーのcharsetを確認します |
CleanPath | リクエストパスからダブルスラッシュをきれいにします |
ゲザーヘッド | 未定義のヘッドリクエストを自動的にルーティングして、ハンドラーを取得します |
ハートビート | 監視エンドポイントサーバーパルスを確認します |
ロガー | 経過処理時間で各リクエストの開始と終了を記録します |
ノーキャッシュ | クライアントがキャッシュを防ぐために応答ヘッダーを設定します |
プロファイラー | ネット/http/pprofをルーターに簡単に取り付けます |
Realip | http.requestのremoteaddrをx-real-ipまたはx-forwarded-forに設定します |
回復者 | パニックを優雅に吸収し、スタックトレースを印刷します |
requestid | 各リクエストのコンテキストにリクエストIDを挿入します |
リダイレクトスラッシュ | ルーティングパスでスラッシュをリダイレクトします |
ルートヘッダー | リクエストヘッダーのルート処理 |
setheader | 応答ヘッダーキー/値を設定するためのショートハンドミドルウェア |
ストリップスラッシュ | ルーティングパスのストリップスラッシュ |
日没 | サンセットは、非推奨/サンセットヘッダーを応答しました |
スロットル | 同時リクエストの数に天井を置きます |
タイムアウト | タイムアウトの締め切りに到達したときにリクエストコンテキストへの信号 |
urlformat | URLからの拡張を解析し、リクエストに合わせてコンテキストに配置します |
withvalue | リクエストコンテキストにキー/値を設定するためのショートハンドミドルウェア |
追加のパッケージについては、https://github.com/go-chiをご覧ください。
パッケージ | 説明 |
---|---|
cors | クロスオリジンリソース共有(CORS) |
docgen | 実行時にchi.routerルートを印刷します |
jwtauth | JWT認証 |
静水剤 | ドメイン/ホストベースのリクエストルーティング |
httplog | 小さいが強力な構造化されたHTTP要求ロギング |
httprate | HTTP要求レートリミッター |
httptracer | HTTPリクエストパフォーマンストレースライブラリ |
httpvcr | 外部ソースの決定論的テストを作成します |
スタンピード | HTTPリクエストコーレスサー |
context
、コールスタックとゴロウチン全体でシグナルコンテキストにシンプルなインターフェイスを提供する小さなPKGです。もともとはSameer Ajmaniによって書かれており、Go1.7以来Stdlibで入手できます。
詳細については、https://blog.golang.org/contextをご覧ください
そして..
ベンチマークスイート:https://github.com/pkieltyka/go-http-routing-benchmark
2020年11月29日の結果、Linux AMD 3950XでGO 1.15.5があります
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
他のルーターとの比較:https://gist.github.com/pkieltyka/123032F12052520AACCAB752BD3E78CC
注:上記のベンチマークのallocsは、http.request WithContext(context.Context)
Context()
)メソッドへの呼び出しからのものです。物体。これは、GOのリクエストにコンテキストを設定する方法です。
私たちはあなたの貢献を見てうれしいです!
Chiは単なるHTTPルーターであり、多くの小さなレイヤーにリクエスト処理を分解できます。多くの企業は、Chiを使用して、公共のAPIのために休憩サービスを書きます。しかし、RESTはHTTPを介して州を管理するための慣習にすぎません。完全なクライアントサーバーシステムまたはマイクロサービスネットワークを作成するために必要な他の多くの作品があります。
休息を超えて、私はフィールドでいくつかの新しい作品をお勧めします:
Copyright(c)2015-Present Peter Kieltyka
MITライセンスに基づいてライセンスされています