【Go】headerタグの使い方
はじめに
前回の記事では、さまざまな構造体タグについて紹介しました。
ただ、実はまだ触れていないタグが1つあります。それがheaderタグです。
今回は、このheaderタグの使い方を紹介します。
↓前回の記事はこちら↓
この記事でわかること
- Echoでのリクエストヘッダーの値の取得方法
-
headerタグの使い方 -
headerタグを使うときの注意点
Echoにおける一般的なリクエストヘッダーの取得
今回は example:aaaというヘッダーを付け、その値を取得してみます。
一般的な方法は以下の通りになるかと思います。
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/header", func(c echo.Context) error {
a := c.Request().Header.Get("example")
return c.JSON(http.StatusOK, a)
})
e.Logger.Fatal(e.Start(":8080"))
}
curl -H 'example:aaa' http://localhost:8080/header
# 出力結果: "aaa"
なお、Getの引数は大文字・小文字を区別しません。
たとえばGet("Example")でもaaaが返されます。
headerタグを使ったリクエストヘッダー取得
Echoの公式ドキュメントには、以下のような記載があります。
Parsing request data is a crucial part of a web application. In Echo this is done with a process called binding. This is done with information passed by the client in the following parts of an HTTP request:
- URL Path parameter
- URL Query parameter
- Header
- Request body
Echoでは、ヘッダーもバインディング対象です。
ただし、ヘッダーのバインディングは他と異なり、以下の注意点があります。
Note that headers is not one of the included sources with Context#Bind. The only way to bind header data is by calling BindHeaders directly.
ざっくりいうと、headerタグを構造体フィールドに付与したとしても、Bindメソッドではリクエストヘッダーをバインドすることができないということです。
それではどのように取得するのか、それは以下の通りとなります。
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
type Header struct {
Example string `header:"example"`
}
func main() {
e := echo.New()
e.GET("/header", func(c echo.Context) error {
h := Header{}
if err := (&echo.DefaultBinder{}).BindHeaders(c, &h); err != nil{
return c.JSON(http.StatusBadRequest, err)
}
return c.JSON(http.StatusOK, h.Example)
})
e.Logger.Fatal(e.Start(":8080"))
}
curl -H 'example:aaa' http://localhost:8080/header
# 出力結果: "aaa"
headerタグを使うときは、(&echo.DefaultBinder{}).BindHeaders(c, &h)を用いてバインドする必要があります。
ですので、以下はアンチパターンとなります。
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
type Header struct {
Example string `header:"example"`
}
func main() {
e := echo.New()
e.GET("/header", func(c echo.Context) error {
h := Header{}
if err := c.Bind(&h); err != nil{
return c.JSON(http.StatusBadRequest, err)
}
return c.JSON(http.StatusOK, h.Example)
})
e.Logger.Fatal(e.Start(":8080"))
}
curl -H 'example:aaa' http://localhost:8080/header
# 出力結果: ""
両者の違い
Echoでリクエストヘッダーを取得する方法として2通りの方法を確認しました。
これらの違いやそれぞれの特徴は以下の通りです。
| 方法 | 概要 | 向いているケース |
|---|---|---|
c.Request().Header.Get("key") |
ヘッダーを1つずつ手動で取得する | 軽量に済ませたい時、1~2個程度の取得 |
(&echo.DefaultBinder{}).BindHeaders(c, &struct) |
構造体にheaderタグを使って一括でバインドする |
複数ヘッダーの管理、バリデーションとの連携、再利用性重視の設計 |
c.Request().Header.Get()の特徴
- Goの標準機能を使って直接ヘッダーを取り出す
- 書き方がシンプル
- 小規模用途に向いている
BindHeaders()の特徴
- 構造体を使ってヘッダーの設計を明示的に記述できる
- 複数のヘッダーがある場合に冗長にならず、保守性が高い
- バリデーションパッケージ(
echo.Validator)と連携しやすい
たとえば Authorization や X-Request-ID など、単発のヘッダーを取得するだけであれば Header.Get()が便利ですが、業務用APIで複数のヘッダーを扱いたい場合やバリデーションをかけたい場合は、BindHeaders()のほうが適しています。
✅まとめ
今回は、headerタグを使ったリクエストヘッダーの取得方法について見ていきました。
一般的にリクエストヘッダーはc.Request().Header.Get("key")で取得できます。
一方で、headerタグを構造体に付与してバインドすることもできますが、c.Bind()ではなく、DefaultBinder{}.BindHeadersを明示的に呼び出す必要があります。
シンプルな用途にはHeader.Get()、複数ヘッダーや再利用性が必要な場面ではBindHeaders()を使い分けましょう。
✏️参考
Discussion