json昔以下の様な記事を書いていた。goでJSONのunmarshal時のrequiredなfieldの扱いについてリンク先の記事ではpointerを使わないstruct定義に対してUnmarshalJSONを自前で定義することでどうにかやろうという感じのものだった。このリンク先の記事の実装ではエラーメッセージに不備があった(後述する)。これを改善できるかもしれない方法を思いついたのでそのメモ。pointerが必要になってしまうのか?その前に前提の確認。pointerが必要になってしまうのかというとこれはzero値との兼ね合いのため。以下のパッケージなどはゼロ値をunrequiredだと割り切った実装になっている。API用のvalidationなどを考えた場合にはこれではちょっと困る。具体的にはbooleanを含んだfieldのPATCH。PATCHは部分更新なのである対象を更新したいと思った時にその対象の持つフィールドの一部だけがリクエストのボディなどとして渡される。このときのフィールドの更新後の未来は以下3つの可能性が存在する(ここではあるbooleanフィールドxを対象に考える)。更新しない最後が重要。現在がtrueだったらtrueに、現在がfalseだったらfalseにというように、現在の値を保つような更新のPATCHを投げたいことがある。実際通常は該当するフィールドを含めないPATCHの場合にはそのような動作を期待する。このときbooleanのzero値はfalseではあるのだけれど。falseで更新されてほしくはない。逆にfalseで更新したいこともあるのでunrequired扱いになりエラーということは避けたい。zero値とunrequiredを見分ける方法zero値とunrequiredを区別して取り扱う方法は2つある。1つはpointerを使う方法で、もう1つは新しい型を定義する方法。後者はdatabase/sqlが行っている方法。NullBool}例えばNullBoolの例ではValidがtrueの場合にはnullではない(unrequiredではない)。ポインタを使う方法もある。go-swaggerなどはこちがわの定義。過去の記事ではUnmarshalJSONを自分で定義し。そのメソッドの中だけでpointerを使った表現にマッピングしてからvalidationを行うという方法で解決していた。nil}これが一見良いと思われるもののネストした構造のエラーのときにあまりうれしくない。ネストした構造中でエラーがあった場合(先程の例ではfatherの中でエラーがあった場合)、本来ならば全体の構造を現してのエラーメッセージを表示したいところがエラー箇所部分のみの表示になってしまう。具体的には以下の様なJSONを渡してのエラーは以下のようになってしまう。"bar"}}これをUnamarshalJSONしたときのメッセージ。"bar"}father部分の不備なのにも関わらずfatherの情報が消えてしまっている。json.RawMessageを利用するここまでは概ね前回のおさらいみたいなもの。考えて見た所encoding/json.RawMessageを利用すればエラーメッセージを改善できそうなことに気づいた。ネスト部分をRawMessageの型にしてあげて遅延させてあげる。すると以下のようなエラーメッセージのエラーが作れる。errorの表示としては悪くない。今回はfatherもエラーメッセージに含まれている。"bar"}このときのコード。nil}よりキレイなエラーの表示あとはerrorをlistと見做したようなエラー表現やあるいはmapと見做したエラー表現にマッピングしてあげればネストしたエラー表現は作ることができる。以下の様な表示のエラーも作ることができる。error:{"father":{"name":"required"},"mother":{"name":"required"}}ということが分かったのでこのようなコードを出力するライブラリを作ってみても良いかもしれない。追記ただしまだ課題がある。true/false/undefined的な3値に対して無視するという意味でのnilを許せない。(requiredに対応できるがunrequiredに対応できない)。生成されるUnmarshalJSONのコードを短くした。開発中で完成はしていないですが。componentという機能を追加した月別アーカイブはてなブログをはじめよう!podhmoさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。