post Image
Goのhttpルーター「Chi」の紹介

少し遅れてしまいましたが、Origami Advent Calendar 2016の21日目の記事になります。

OrigamiではGo言語をメインの言語として、APIなどのHTTPアプリケーションサーバを作製しています。

golangでHTTPアプリケーションを作成するときには
フレームワークを特に導入しなくとも、
net/httpとそれに準拠したライブラリを組み合わせれば十分だと考えています。

基本的にはnet/httpの機能の組み合わせで大抵の機能は十分表現できます。
ただし、ルーティングについては標準のhttp.ServeMuxだとちょっとつらいことが多いと思います。
標準のAPIに準拠しつつ、実アプリケーションでも十分な機能を備えたルーティングライブラリはいくつかあります。

Origamiのいくつかのアプリケーションサーバでは、そのうちのchiを利用しています。

chi

https://github.com/pressly/chi

chinet/httphttp.Handlerインターフェースに準拠したルーティング・ライブラリです。

標準のhttp.ServeMuxと比較して以下のような機能があります。

  • ワイルドカード付きパターンのサポート
  • 名前付きパラメータのサポート
  • ミドルウェアのサポート

ルーティング・ライブラリとしての特色は他に以下があります。

  • Go 1.7 で追加されたcontextパッケージに準拠
  • net/httpのインターフェースに準拠
  • Go 1.7とnet/httpにのみ依存
  • パトリシア木による高速マッチ(httprouterと同じ)

golangの標準インターフェースに準拠しており、かつ、ある程度高速で柔軟なマッチングのできるルータがほしいなら、chiはかなりおすすめできるライブラリです。

実際、chiの採用事例としては以下のような企業があります。

  • CloudFlare
  • Heroku
  • Origami

chiの利用

chiの使い方は単純で、ルータを作成してnet/httpのサーバにマウントするだけです。

package main

import (
    "net/http"
    "github.com/pressly/chi"
)

func main() {
    r := chi.NewRouter()
    http.ListenAndServe(":80", r)
}

ルータへのハンドラの追加は以下のように行います。

// 標準のHandlerインターフェースを受け取ります.
var handler http.Handler = someHandler
r.Handle("/foo", handler)

// HandlerFunc型で受けることもできます.
var handlerF http.HandlerFunc = someHandler.ServeHTTP
r.HandleFunc("/bar", handlerF)

// 特定のメソッドのみ受け取るメソッドも用意されています.
// HTTPメソッドでのルーティングは、HandlerFuncを指定することに注意してください.
r.Get("/baz", handlerF)

ワイルドカードや名前付きパラメータを受け取ることもできます。

r.Get("/users/:id/*", func(w http.ResponseWriter, r *http.Request) {
  userID := chi.URLParam(r, "id")
  // ...
})

サブルータを作ることもできます。

subr := chi.NewRouter()
subr.Get("/bar", FooBarHandler)
r.Mount("/foo", subr)
// => /foo/bar へのリクエストは FooBarHandler に送られます.

// サブルータは以下のように作成することもできます.
r.Route("/foo", func(subr chi.Router){
  subr.Get("/bar", FooBarHandler)
})

Middleware

chiはmiddlewareパターンによるミドルウェア(プラグイン)を利用することができます。
middlewareパターンとは以下のようにhttp.Handlerをラップする関数を指します。

// http.Handlerを受け取って、前後に何らかの処理を足し、
// ラップした新しいhttp.Handlerを返すような関数を
// middlewareと呼びます.
func middleware(next http.Handler) http.Handler {
  // ※http.HandlerFunc型の関数はhttp.Handlerインターフェースを持ちます.
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    // 前処理
    next(w, r)
    // 後処理
  })
}

middleware関数を通すことで様々な共通処理をハンドラに追加することができます。

var newHandler1 = middleware(originalHandler1)
var newHandler2 = middleware(originalHandler2)
// ラップしたハンドラをマウント
// newHandler1, newHandler2はそれぞれmiddlewareに実装された処理を共通して持つ.
r.Get(pattern1, newHandler1)
r.Get(pattern2, newHandler2)

chiではこのようなmiddleware関数の適用を自動で行ってくれます。

// middleware1は全体に適用されます
r.Use(middleware1)
r.Get("/foo", handler1)

// サブルータを作成してミドルウェアを追加することもできます.
// サブルータに適用されたミドルウェアはサブルータのみ有効です.
r.Route("/bar", func(subr chi.Router) {
  subr.Use(middleware2)
  subr.Get("/baz", handler2)
})

// 適用されるミドルウェア
// /foo => middleware1
// /bar/baz => middleware1, middleware2

chiでは上記のmiddlewareパターンを適用したミドルウェアがいくつか用意されいて、
chi/middlewareサブパッケージにまとめられています。

例えばmiddleware.RequestIDはRequestIDをそれぞれのリクエストにセットします(context経由で取り出せます)。
middleware.Timeoutはタイムアウト機能を提供します。
他にも便利なパッケージがあるので自分で実装する前にこれらのパッケージを利用してもよいでしょう。

おわりに

chiはシンプルですが非常に有用なルーティングライブラリです。

Goでは巨大なライブラリやフレームワークを使うより、
こういったシンプルなコンポーネントを組み合わせていく方が、
より「Goらしい」スタイルではないかと思っています。

その意味でnet/httpと組み合わせやすいchiは非常に取り回しがよく、
採用して安心感が持てました。


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。