🔷
go-json/optパッケージを公開しました

皆さんはじめまして、ディップ株式会社の町田です。 R&D推進室でGoを使った開発とその支援をしています。
今回はとあるGoのパッケージを公開しましたのでその紹介をしたいと思います。 Goの経験者向けの内容になってしまっていますが、最後までお付き合いいただけると幸いです。
go-json/opt
今回公開したパッケージは以下になります。 github.com
こんなことができます
JSONをUnmarshalした構造体から、元のJSONのフィールド有無を判定できるようになります。
例えば、以下のリクエストをJSONで受けるユーザー更新APIがあったとします。
項目名
型
必須
user_id
数値
◯
user_name
文字列
-
age
数値
-
リクエストを受ける構造体を基本の型で定義すると
type Request struct {
UserID int32 \`json:"user\_id"\`
UserName \*string \`json:"user\_name"\`
Age \*int32 \`json:"age"\`
}
JSONフィールドの有無を判別することができなくなります。
var req Request
// user\_nameフィールド有り、値がnullの場合
\_ = json.Unmarshal(\[\]byte(\`{"user\_id": 1, "user\_name": null, "age": 25}\`), &req)
fmt.Println(req.UserID) // 1
fmt.Println(req.UserName) // nil
fmt.Println(req.Age) // 25
// user\_nameフィールド無しの場合
\_ = json.Unmarshal(\[\]byte(\`{"user\_id": 1, "age": 25}\`), &req)
fmt.Println(req.UserID) // 1
fmt.Println(req.UserName) // nil
fmt.Println(req.Age) // 25
更新対象の項目がJSONにフィールドが設定されているものに限定する(差分のみが渡ってくる)仕様の場合、困ったことになります。 前者はuser_nameをnullに更新し、後者はuser_nameは更新対象外とする必要がありますが、 どちらもUserName=nilになってしまうため、更新対象か否かが判断できません。
optパッケージで解決できます
リクエストを受ける構造体でgo-json/optパッケージを利用します
import "github.com/dip-dev/go-json/opt"
type Request struct {
UserID int32 \`json:"user\_id"\`
UserName opt.String \`json:"user\_name"\`
Age opt.Int32 \`json:"age"\`
}
optパッケージではHasKeyメソッドを参照することでフィールドの有無を判定することができます。
var req Request
// user\_nameフィールド有り、値がnullの場合
\_ = json.Unmarshal(\[\]byte(\`{"user\_id": 1, "user\_name": null, "age": 25}\`), &req)
fmt.Println(req.UserID) // 1
fmt.Println(req.UserName.Value()) // nil
fmt.Println(req.UserName.HasKey()) // true
fmt.Println(req.Age.Value()) // 25
fmt.Println(req.Age.HasKey()) // true
// user\_nameフィールド無しの場合
\_ = json.Unmarshal(\[\]byte(\`{"user\_id": 1, "age": 25}\`), &req)
fmt.Println(req.UserID) // 1
fmt.Println(req.UserName.Value()) // nil
fmt.Println(req.UserName.HasKey()) // false
fmt.Println(req.Age.Value()) // 25
fmt.Println(req.Age.HasKey()) // true
フィールドが無い項目はHasKey()がfalseとなるため、処理分岐が可能となります。
おわりに
基本的な型は全て対応していますが、rune等の一部の型には対応していません。 詳細な使い方についてはREADMEを参照ください。
こちらのパッケージが少しでも皆さんの開発のお役に立てれば嬉しいです。
Discussion