golang で net/http とってきて JSON を parse して所定のキーを取り出すプログラムを書きたかった。 こういう場合、JSONPath とか使って書きたいのだが、JSONPath が完全にサポートされている go のライブラリは見当たらなくて、mattn_jp さんが JSONPath 書こうとして途中でやめた gist がひっかかってくる程度。あとなんか yasuyuky/jsonpath というのもあるのだが、これはいわゆる JSONPath ではない。
JSONPath なくてマジ不便ヤンケ、と思っていたが、mattn_jp さんが go-scan というライブラリを書いていた。
golangのjson、型を作るかmap[string]interface{}にしてキャストするしかなくて最初はgolang面倒臭いなって思ってたけど小規模なら後者で十分だしそれ以上の規模なら型作った方が後々必ず得する。さらにgo-scanもあるのでその汚名はもう拭われた。
— mattn (@mattn_jp) September 4, 2013
というわけで、go-scan がマジ便利。
https://github.com/mattn/go-scan
以下は metacpan の API にアクセスして、必要な情報を取り出すサンプルである。 マジ便利。 @mattn_jp++
func getRepositoryUrl(module string) (repositoryUrl string, err error) {
var s string
url := fmt.Sprintf("http://api.metacpan.org/v0/module/%s?join=release",
url.QueryEscape(module))
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
var v interface{}
err = json.Unmarshal(body, &v)
if err != nil {
return "", err
}
err = scan.ScanTree(v, "/distribution", &s)
if s == "perl" {
return "", fmt.Errorf("%q is provided by core module", module)
}
err = scan.ScanTree(v, "/release/_source/resources/repository/url", &s)
if err != nil {
return "", err
}
return s, nil
} else {
return "", nil
}
}