🔷

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を参照ください。

こちらのパッケージが少しでも皆さんの開発のお役に立てれば嬉しいです。

dipテックブログ

Discussion