ルーティング

Go Fiberフレームワークにおけるルートの役割は、異なるURLを処理関数にバインドし、HTTPリクエスト処理をサポートすることです。これはすべてのWebフレームワークリクエストのエントリーポイントとして機能します。

ルートハンドラ(関数)

特定のHTTPメソッドにバインドされたルートを登録します。

注:一部のフレームワークでは、ルートハンドラはコントローラと呼ばれ、一般的には同じ意味を持ちます(着信HTTPリクエストを処理するための関数/メソッドを決定する)。

関数シグネチャ:

// HTTPメソッド
func (app *App) Get(path string, handlers ...Handler) Router
func (app *App) Head(path string, handlers ...Handler) Router
func (app *App) Post(path string, handlers ...Handler) Router
func (app *App) Put(path string, handlers ...Handler) Router
func (app *App) Delete(path string, handlers ...Handler) Router
func (app *App) Connect(path string, handlers ...Handler) Router
func (app *App) Options(path string, handlers ...Handler) Router
func (app *App) Trace(path string, handlers ...Handler) Router
func (app *App) Patch(path string, handlers ...Handler) Router

// メソッドを値として指定できるAddメソッド
func (app *App) Add(method, path string, handlers ...Handler) Router

// すべてのHTTPメソッドにルートを登録する
// app.Useと似ていますが、接頭辞をバインドしません
func (app *App) All(path string, handlers ...Handler) Router

例:

// シンプルなGETハンドラ
app.Get("/api/list", func(c *fiber.Ctx) error {
  return c.SendString("これはGETリクエストです!")
})

// シンプルなPOSTハンドラ
app.Post("/api/register", func(c *fiber.Ctx) error {
  return c.SendString("これはPOSTリクエストです!")
})

UseはミドルウェアとプレフィックスURLインターセプターをロードするために使用されます。これらのルートは各パスの先頭とのみ一致し、たとえば、/john/john/doe/johnnnnnなどに一致します。

カスタムミドルウェアの関数シグネチャ:

func (app *App) Use(args ...interface{}) Router

例:

// すべてのリクエストに一致
app.Use(func(c *fiber.Ctx) error {
    return c.Next()
})

// /apiで始まるリクエストと一致
app.Use("/api", func(c *fiber.Ctx) error {
    return c.Next()
})

// /apiまたは/homeで始まるリクエストと一致(複数のプレフィックスをサポート)
app.Use([]string{"/api", "/home"}, func(c *fiber.Ctx) error {
    return c.Next()
})

// 複数のハンドラを追加
app.Use("/api", func(c *fiber.Ctx) error {
  c.Set("X-Custom-Header", random.String(32))
  return c.Next()
}, func(c *fiber.Ctx) error {
  return c.Next()
})

パス

リクエストメソッドと共に、ルートパスはアクセス可能なエンドポイントを定義します。ルートパスは文字列または文字列パターンであることができます。

文字列ベースのルートパスの例

// このルートパスはルートパス、"/"へのリクエストに一致します
app.Get("/", func(c *fiber.Ctx) error {
  return c.SendString("ルートパス")
})

// このルートパスは"/about"へのリクエストに一致します
app.Get("/about", func(c *fiber.Ctx) error {
  return c.SendString("About")
})

// このルートパスは"/random.txt"へのリクエストに一致します
app.Get("/random.txt", func(c *fiber.Ctx) error {
  return c.SendString("Random.txt")

ExpressJsフレームワークと同様に、宣言された順序にルートが重要です。リクエストが受信されると、ルートは宣言された順序で確認されます。

次の点に注意してください: 変数パラメータを含むルートは、誤って一致することを防ぐために、固定部分を含むルートの後に書かれるようにしてください。これにより予期しない動作が起こることを防ぎます。

ルートパラメータ

ルートパラメータは、ルート内の動的な要素であり、名前付きまたは無名セグメントのいずれかになります。これらのセグメントは、URL内の指定された位置に値をキャプチャするために使用されます。Params関数を使用してこれらの値を取得できます。この関数のパラメータは、パス内のルートパラメータの名前であり、無名のパラメータの場合は文字(*、+)とその数になります。

ワイルドカード(*)またはプラス記号(+)は、貪欲なパラメータを表します。

ルートは、オプションのパラメータを使用する可能性も提供します。名前付きパラメータの場合、これらのパラメータは疑問符(?)に続き、プラス記号はオプションではなく、ワイルドカード文字を使用してオプションで貪欲なパラメータ範囲を表すことができます。

ルートパラメータを使用したルートの定義の例

// パラメータ
app.Get("/user/:name/books/:title", func(c *fiber.Ctx) error {
    fmt.Fprintf(c, "%s\n", c.Params("name"))
    fmt.Fprintf(c, "%s\n", c.Params("title"))
    return nil
})
// プラス - 貪欲 - オプションでない
app.Get("/user/+", func(c *fiber.Ctx) error {
    return c.SendString(c.Params("+"))
})

// オプションパラメータ
app.Get("/user/:name?", func(c *fiber.Ctx) error {
    return c.SendString(c.Params("name"))
})

// ワイルドカード - 貪欲 - オプション
app.Get("/user/*", func(c *fiber.Ctx) error {
    return c.SendString(c.Params("*"))
})

// このルートパスは、リクエスト "/v1/some/resource/name:customVerb" に一致します。なぜなら、パラメータ文字がエスケープされているからです
app.Get(`/v1/some/resource/name\:customVerb`, func(c *fiber.Ctx) error {
    return c.SendString("Hello, Community")
})

ハイフン(-)とピリオド(.)は文字通りに解釈されるため、これらはルートパラメータと一緒に使用して有用な目的を達成するために使用することができます。

すべての特殊パラメータ文字は \ を使用してエスケープすることもできますが、その値は無視されます。したがって、ルートで使用する場合はバッククォート `` を使用することをお勧めします。Goの正規表現のドキュメントでは常に曖昧さがなくなるようにそれらを使用し、エスケープ文字が誤って正規表現パターンに影響を与えないようにします。

// http://localhost:3000/plantae/prunus.persica
app.Get("/plantae/:genus.:species", func(c *fiber.Ctx) error {
    fmt.Fprintf(c, "%s.%s\n", c.Params("genus"), c.Params("species"))
    return nil // prunus.persica
})
// http://localhost:3000/flights/LAX-SFO
app.Get("/flights/:from-:to", func(c *fiber.Ctx) error {
    fmt.Fprintf(c, "%s-%s\n", c.Params("from"), c.Params("to"))
    return nil // LAX-SFO
})

当社のスマートルーティングは、導入されたパラメータ文字がリクエストルートの一部であるべきであることを認識し、それをそのように処理できます。

// http://localhost:3000/shop/product/color:blue/size:xs
app.Get("/shop/product/color::color/size::size", func(c *fiber.Ctx) error {
    fmt.Fprintf(c, "%s:%s\n", c.Params("color"), c.Params("size"))
    return nil // blue:xs
})

また、ルートは複数のパラメータや、複数の連続した無名パラメータ文字、ワイルドカードやプラス文字を使用することができ、これによりユーザーがルートで使用できる可能性が大幅に拡大されます。

// GET /@v1
// Params: "sign" -> "@", "param" -> "v1"
app.Get("/:sign:param", handler)

// GET /api-v1
// Params: "name" -> "v1" 
app.Get("/api-:name", handler)

// GET /customer/v1/cart/proxy
// Params: "*1" -> "customer/", "*2" -> "/cart"
app.Get("/*v1*/proxy", handler)

// GET /v1/brand/4/shop/blue/xs
// Params: "*1" -> "brand/4", "*2" -> "blue/xs"
app.Get("/v1/*/shop/*", handler)

Expressルーティングにルーティングを既に適応させていますが、比較的遅いため、まだ正規表現をサポートしていません。

制約

受信したURLとURLパスがパラメータを介してルート値に分割されると、制約が実行されます。この機能は v2.37.0 で導入され、.NET Core からのインスピレーションを受けています。

制約はパラメータの検証には使用されません。パラメータ値が制約に適合しない場合、Fiber は 404ハンドラ を返します。

制約 一致する例
int :id 123456789、-123456789
bool :active true、false
guid :id CD2C1638-1638-72D5-1638-DEADBEEF1638
float :weight 1.234、-1,001.01e8
minLen(value) :username<minLen(4)> test(少なくとも4文字)
maxLen(value) :filename<maxLen(8)> MyFile(最大8文字まで)
len(length) :filename<len(12)> somefile.txt(12文字)
min(value) :age<min(18)> 19(整数値は少なくとも18である必要があります)
max(value) :age<max(120)> 91(整数値は120を超えることはできません)
range(min,max) :age<range(18,120)> 91(整数値は少なくとも18である必要がありますが、120を超えることはできません)
alpha :name Rick(文字列は1文字以上のアルファベットで構成されている必要があります。大文字小文字を区別しません。a-z)
datetime :dob<datetime(2006\\-01\\-02)> 2005-11-01
regex(expression) :date<regex(\d{4}-\d{2}-\d{2})> 2022-08-27(正規表現に一致する必要があります)

  • 単一の制約
  • 複数の制約
  • 正規表現制約
app.Get("/:test", func(c *fiber.Ctx) error {
  return c.SendString(c.Params("test"))
})

// curl -X GET http://localhost:3000/12 // 12

// curl -X GET http://localhost:3000/1 // GET /1 が見つかりません


複数制約を追加するには `;` を使用できます。

app.Get("/:test", func(c *fiber.Ctx) error { return c.SendString(c.Params("test")) })

// curl -X GET http://localhost:3000/120000 // GET /120000 が見つかりません

// curl -X GET http://localhost:3000/1 // GET /1 が見つかりません

// curl -X GET http://localhost:3000/250 // 250


Fiber はルートを登録する際に正規表現制約のための事前コンパイルを行うため、パフォーマンスには影響しません。

```go
app.Get(`/:date`, func(c *fiber.Ctx) error {
  return c.SendString(c.Params("date"))
})

// curl -X GET http://localhost:3000/125 // GET /125 が見つかりません

// curl -X GET http://localhost:3000/test // GET /test が見つかりません

// curl -X GET http://localhost:3000/2022-08-27 // 2022-08-27


> 日付時刻の制約(`*`,`+`,`?`,`:`,`/`,``,``,`>`,';`,`(`,`)`)を使用する場合は、特別な文字をルートで使用する前に、誤解を避けるために `\\` を使用してください。

**オプションパラメータの例**

オプションのパラメータにも制約を追加できます。
```go
app.Get("/:test?", func(c *fiber.Ctx) error {
  return c.SendString(c.Params("test"))
})
// curl -X GET http://localhost:3000/42
// 42
// curl -X GET http://localhost:3000/
//
// curl -X GET http://localhost:3000/7.0
// GET /7.0 が見つかりません

ミドルウェア

リクエストやレスポンスを操作するために設計された機能は ミドルウェア関数 と呼ばれます。Next は、現在のルートに一致する next 関数を実行する Fiber ルーティング関数です。

ミドルウェア関数の例

app.Use(func(c *fiber.Ctx) error {
  // すべてのレスポンスでカスタムヘッダーを設定する:
  c.Set("X-Custom-Header", "こんにちは、世界")

  // 次のミドルウェアに進む:
  return c.Next()
})

app.Get("/", func(c *fiber.Ctx) error {
  return c.SendString("こんにちは、世界!")
})

Use メソッドのパスは マウントパス または プレフィックス パスであり、そのパスで始まるリクエストにのみミドルウェアが適用されるように制限します。

ランタイムでのルート制限の追加

設計上の考慮事項やパフォーマンスの観点から、アプリケーション起動後に動的にルートを追加することはサポートされていません。アプリケーションが起動する前にすべてのルートが定義されていることを確認してください。

グルーピング

多くのエンドポイントがある場合、Group を使用してルートを整理できます。

func main() {
  app := fiber.New()

  api := app.Group("/api", middleware) // /api

  v1 := api.Group("/v1", middleware)   // /api/v1
  v1.Get("/list", handler)             // /api/v1/list
  v1.Get("/user", handler)             // /api/v1/user

  v2 := api.Group("/v2", middleware)   // /api/v2
  v2.Get("/list", handler)             // /api/v2/list
  v2.Get("/user", handler)             // /api/v2/user

  log.Fatal(app.Listen(":3000"))
}