Go/Ginでmessagepackを使う

いろんな言語を少しでいいから触ってみようという、ライトな感じでGo言語を触り始め、 フレームワークは速度に定評のあるGinを使ってみようということでGo/Ginの勉強をしばらくやっていましたが、
APIを作っていた時に、messagepackでシリアライズ・デシリアライズしてリクエストを受けたりレスポンスをしたりしたくなりました。
調べて判明するまでは時間かかりましたけど、わかっちゃうと割とすぐ対応できたのでメモしますよ

Ginの機能でmessagepackを使う情報があまりない

Go/GinでAPIを調べてみると、大体は

c.JSON()
のようにJSONでレスポンスしたり、
type Request struct {
  Param1 int `json:"param1"`
  Param2 string `json:"para21"`
}
を使ってJSONリクエストからパラメータを取得したりと、JSONベースの情報がヒットしました。
一方、messagepackを使ってリクエストのデシリアライズやレスポンスのシリアライズといった情報がヒットしませんでした。
ヒットする情報といえば、Ginとしての処理の仕方というよりも、 Go言語のmsgpackパッケージをインポートしてどうこうという情報がほとんどなので、 どうやってGinを使ったやり方に落とし込むのかがわからなかったんですね...
色々ググっても出てこないので、GinがどうやってJSONの受け取りとレスポンスをしているのかを調べて、 これをmessagepack向けにアレンジする方向で対応しようとしました。

ソースコード解析をしたら下回りがあった

Ginのパッケージを構成するソースコードはgithubで公開されているため、 JSONの受け取りとレスポンスの仕組みの解析にあたり、github上のソースコードを読んでみました。
すると、JSONをはじめとしていろいろなフォーマットに対応できるように下回りがきっちりしている印象を受け、 この中にmessagepackに対応した下回りが紛れているのでは?と思ったんですね。
試しにmessagepackをキーワードにgrepしてみたところ、、、ありました。すでに下回り実装済みです。
ということは、下回りの呼び出し方さえ分かれば、もうmessagepackへの対応は終わったも同然ですね。

Ginでmessagepackをレスポンス

gin-gonic/gin/render/msgpack.go
を中心に解析をしたところ、

c.Render(code int, render.MsgPack{Data:response})
でレスポンスができました。実際に使う時は、importを含めるとだいたいこんな感じですね。
import(
      "github.com/gin-gonic/gin"
      "github.com/gin-gonic/gin/render"
 )

func Response(c *gin.Context, code int, res interface{}) {
    c.Render(code, render.MsgPack{Data:res})
}

Ginでmessagepackリクエスト受け取り

c *gin.Context
にはBindJSONがあるので、messagepackにバインドするインターフェースもあるかと思ったけど残念ながら見当たらず。
ただ、bindingの種別にMsgPackがあるので、バインドするインターフェースMustBindWithにMsgPackとして渡してあげれば解決します。

import(
      "github.com/gin-gonic/gin"
      "github.com/gin-gonic/gin/binding"
 )

func GetRequestParams(c *gin.Context, obj interface{}) {
    return c.MustBindWith(obj, binding.MsgPack)
}

func Hoge(c *gin.Context) {
    var request requestParams
    GetRequestParams(c, &request) // requestにリクエストパラメータがバインドされる
}

おわりに

これを書いてるときはgo version 1.16の時でしたけど、いずれはこんなことしなくてもmessagepackに簡単に対応するインターフェースが作られるのではと 勝手に思ってます