💻

Go: json パッケージ Marshaler/Unmarshaler の実装例

LayerX インボイス を開発しているDX事業部の @yyoshiki41(中川佳希)です。
今回は、json パッケージにある  インターフェイスを満たす構造体を用いたアプリケーション実装の例を紹介します。

MarshalerUnmarshaler インターフェイス

Go ではインターフェイスを命名する際、実装されたメソッド名や構造体名の末尾に  を付ける慣習があります。  も下記のようなメソッドを実装するインターフェイスとして定義されています。
 は、インプットの json データをハンドルして Go の型へ変換したい時など、 は、その構造体を json データとしてシリアライズして出力する際などに利用できます。

例. 文字列 "2021-08-31" を  型へ。json 出力時には "2021-Aug-31" へ。

アプリケーションでの実装例

店舗側画面での権限を管理するアプリケーションを想定してみましょう。 各ユーザー(店舗のスタッフ)に対して、画面ページ(やデータソース)毎に権限を与えるものです。

UI イメージ

UIクライアント側では、真偽値としてデータを解釈することが先に決まります。
サーバーサイドAPI、DB側ではどのようなデータの持ち方をするでしょうか? 今後もUIが必要とするAPIやデータリソースは変化するという前提とします。

DB

UI で必要となるデータ構造は上でも述べたように真偽値です。
クライアントからのリクエストを保存する際は、UI側と同じ json データでDBに保存しています。(UI側のフォームの部品などが変わった場合にはバージョニングなどで対応が必要です。)

サーバーサイドAPI

アプリケーションコード側ではどのようにこのデータを扱うか? 真偽値によって、アクションを制御できるよう検討してみます。
例えばショップ情報の閲覧権限()が、
  •  であれば、  という RestAPI へのリクエストが可能
  •  であれば、リクエストに対してステータスコード  を返す
という具合です。
今回は、json パッケージのカスタム / で解決する方法を考えてみたいと思います。
許可されているAPIエンドポイントを表す構造体をスライスで持つ  構造体を実装します。 (この構造体は、 / インターフェイスを満たしています。)
真偽値を用いてアクセスコントロールを行うミドルウェアなどでは、DB から取得してきた json を  して、API エンドポイント構造体のスライスにしてハンドル出来るようになります。(真偽値で  の場合には、スライスの要素数が0として表現されます。)

まとめ

/ を実装する構造体の実装例を作成していきました。 raw そのままでは扱いにくい json データも、アプリケーションコードで扱いやすい構造体に変換することが出来ます。 もしくは、構造体から json にシリアライズするなどが出来ると必要なコードをスッキリさせたり、ロジックの変化にも対応しやすくなります。
LayerX インボイスでは、 go generate と組み合わせてアクセスコントロールなどに使っています。
  • API エンドポイント一覧は、swagger 定義から生成
  •  は、 UI コンポーネントのフォームから生成
  •  メソッドの実装は、コード生成と相性の良い汎化できる分岐ロジック
開発スピードに耐えれる、変更に強い設計を今後も追求できればと考えています。
興味が湧いたという方は、ぜひ一度話を聞きに来てみてください。
エントリーはちょっとという方、こちらから中の話を聞くこともできます!