今日書くのは、先日Go言語の個人プロジェクトである Pixela に手を加えた際に実感したことについて。
先日手を加えたものの一部に、以下のようなものがあった。
> 以下のようなコマンドを実行してみましょう。>> curl -X GET https://pixe.la/v1/users/a-know/graphs/stopwatch-test/20200504 -H 'X-USER-TOKEN:thisissecret'>> Pixela では、各日付ごとのデータを pixel と呼んでいるのですが、その詳細を取得できるコマンドです。`20200504` のところは詳細を確認したい日付を指定します。このコマンドの実行がうまくいけば、以下のような結果が表示されると思います。>> {"quantity":"0.50","optionalData":"{\"stopwatchUsage\":{\"stopwatchUseCount\":2,\"stopwatchPeriods\":[\"20:04:48 - 20:05:00\",\"20:05:13 - 20:05:30\"]}}"}>> quantity というのはその日の計測時間の合計値のことです。一方、optionalData に指定されているのは JSON 形式で表されたオブジェクトで、stopwatchUseCount には「計測開始&終了を何セット実施したか」というカウントが、stopwatchPeriods には「計測対象となった時間帯」が、それぞれ記録されています。上記の例だと、「計測開始&終了を2セット」「計測したのは 20時04分48秒〜20時05分00秒 と 20時05分13〜20時05分30秒」という情報がセットされている形になります。
Pixel
という以下のような(とはいえ、説明に不要なものは省略している。)エンティティがあって、
type Pixelstruct { Datestring`json:"date"` Quantitystring`json:"quantity"` OptionalDatastring`json:"optionalData"`}
このうちOptionalData
は、ユーザーが自由にJSON文字列を格納することができる、という仕様。そんな仕様だったところに、今回のアップデートで、システム側もOptionalData
を用いるようにしたくなった、ということになる。
ざっくり要件をまとめるとすると、以下のような感じだろうか。
OptionalData
を Unmarshal したものに、"stopwatchUsage":{"stopwatchUseCount":1,"stopwatchPeriods":["20:00:00 - 20:05:00"]}
といったオブジェクトを突っ込みたい。OptionalData
にもともと格納されていた情報は、もちろん維持しなければならない。stopwatchUsage
と重複するケースは考慮しない(システム側が上書きすることを許容する)最初に行き着いた情報はこちらgolang は ゆるふわに JSON を扱えまぁす! — KaoriYa 。ただ、ここにある方法だと、全くの未知の構造のオブジェクトに対して適用することができないように思われた(これはこれで便利に使える場面はあるものだと感じたけれど)。
ただ、上記のページ内で紹介されていたmattn/go-jsonpointer が、まさに今回のケースでぴったりハマりそうなもので、実際、これを使うことで非常にすんなり実装を終えることができた。
JSON Pointer の GO実装。以下に、今回のケースにおいてこれを用いた実例を示す。
以下のように、OptionalData
に突っ込みたい struct を予め用意しておき、
count :=1periods := []string{"20:00:00 - 20:05:00"}usage := &stopwatchUsage{ StopwatchUseCount: count, StopwatchPeriods: periods,}
*interface{}
を渡してOptionalData
を Unmarshal。
var objinterface{}json.Unmarshal([]byte(pixel.OptionalData), &obj)
あとは、Unmarshal されたものに対して go-jsonpointer を使って、stopwatchUsage
というキーで set してやるだけでよかった。
jsonpointer.Set(obj, "/stopwatchUsage", usage)optinalDataString, err := json.Marshal(obj)
/stopwatchUsage
というのがJSON Pointer(RFC6901 として標準化された、JSONオブジェクトに対するクエリ文字列)。
他にも、Get
Remove
ができる。リポジトリの README に非常に簡潔に書いていただいていたので、迷うことも何もなかった。「OptionalData
、なんでそんな自由な項目にしたんや......ワイのバカ!」なんて後悔することもなくて、本当に良かった(反省はしたほうがよさそう)。感謝です。
"カスタマー x エンジニアリング" なお仕事に取り組み始めて、はやn年。今は SmartHR でソフトウェアエンジニアをしています。岡山県倉敷市でフルリモートワーク。 個人プロジェクトとして Pixelahttps://pixe.la/ , Okayama.なんかhttps://okayama-nanka.org/
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。