GolangでJSON形式のWebAPIをたたいてCSVを出力する
はじめに
職場でGolangのCLIツール開発を学んでいる。自宅で復習のため,簡単なスクリプトを組んでみた。
概要
- 地点名とidの対応を表すJSONファイルから,地点のidを取得する
[ { "city_name": "稚内", "id": "011000" }, { "city_name": "旭川", "id": "012010" },
- お天気Webサービスにアクセスし,JSONデータを取得する
- 各地点の天気予報の3日分の最高気温を取得する
- 取得するJSONデータにはnull値が含まれる場合がある
- アクセスする時間帯により2日分のデータしか含まれない場合がある
- 全国の地点の最高気温を表すCSVデータを出力する
city,id,2019-05-18,2019-05-19,2019-05-20 稚内,011000,,20, 旭川,012010,,27, 留萌,012020,,24,
実装パターン1
- 利用ライブラリは以下の通り
import ( "encoding/csv" "encoding/json" "io/ioutil" "log" "os" "github.com/franela/goreq" )
- encoding/jsonライブラリではJSONのパースをGolangの構造体のオプションを介して行うため,構造体の宣言が必要だった。
- 構造体を組むのが手間だったので,この記事を参考にしつつ,json-to-goというWebツールを利用した。
type City struct { Name string `json:"city"` ID string `json:"id"` } type Item struct { PinpointLocations []struct { Link string `json:"link"` Name string `json:"name"` } `json:"pinpointLocations"` Link string `json:"link"` Forecasts []struct { DateLabel string `json:"dateLabel"` Telop string `json:"telop"` Date string `json:"date"` Temperature struct { Min interface{} `json:"min"` Max struct { Celsius string `json:"celsius"` Fahrenheit string `json:"fahrenheit"` } `json:"max"` } `json:"temperature"` } `json:"forecasts"` }
- HTTPリクエストおよびItem構造体型変数のフィールドへの値の代入は,goreqライブラリを利用した。
res, _ := goreq.Request{Uri: "http://weather.livedoor.com/forecast/webservice/json/v1?city=" + cityID}.Do() var item Item res.Body.FromJsonTo(&item)
- CSVデータへの出力は標準ライブラリを利用して行った。
file, err := os.Create("output.csv") if err != nil { panic(err) } writer := csv.NewWriter(file) if err != nil { panic(err) } writer.WriteAll(allCityDataSlice)
実装パターン2
- 利用ライブラリは以下の通り。
import ( "encoding/csv" "io/ioutil" "net/http" "os" "github.com/bitly/go-simplejson" )
- HTTPリクエストにあたり,本実装ではgoreqではなく標準ライブラリのnet/httpを利用した。
- 実装パターン1と異なり構造体を経由しない。以下の実装では次のようなことを行っている。
res, err := http.Get("http://weather.livedoor.com/forecast/webservice/json/v1?city=" + cityID) if err != nil { panic(err) } body, err := ioutil.ReadAll(res.Body) if err != nil { panic(err) } resJSON, err := simplejson.NewJson(body) if err != nil { panic(err) }
おわりに
- 構造体を宣言しない分,行数を圧縮できるので,go-simplejsonを利用する実装パターン2のほうが良いかもしれない。
- とはいえ実装パターン1は,構造体のフィールドへのアクセスを利用してデータを操作するので,直感的に素早くコーティングできる利点も感じた。
補足と感想
- 本記事を書き終わるタイミングで発見した記事。本記事と異なり「interface を利用して局所的に参照する」方法を紹介している。
- こんな記事も見つけた。眺めるだけで面白そう。
- Software Design5月号はGolang特集。CLIツール開発入門の記事もある。
- 作者: 上田拓也,mattn,渋川よしき,鹿志村秀昭,曽利雅樹,舟窪恵一,向山優,安井正明,渡部敏雄,根本祐介,座間政紀,吉田英二,安藤幸央,結城浩,武内覚,宮原徹,平林純,くつなりょうすけ,中島明日香,上川慶,職業「戸倉彩」,中村壮一,田代勝也,山田泰宏,上田隆一,嶋是一,小飼弾,青田直大,あわしろいくや,中島雅弘,横田結菜,西谷友彬,大塚和彦,後藤大地,杉山貴章,Software Design編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2019/04/18
- メディア: 雑誌
- この商品を含むブログを見る
- Golangは変数や関数の宣言で細かく型を書く。そのため調べ物の際に読むソースコードがとても読みやすい。初心者にとってはありがたい。
- 同じ機能のスクリプトを昨年Pythonで書いたので,良い復習になった。
- 久しぶりにブログを書いたが,復習になるだけでなく,執筆の過程で付加的な情報が色々と集まってくる。
- 少しずつレベルを上げつつ,色んなツールを今後開発したい。