Minarai Tech Blog

プログラミング初心者の備忘録

GolangでJSON形式のWebAPIをたたいてCSVを出力する

はじめに

職場でGolangCLIツール開発を学んでいる。自宅で復習のため,簡単なスクリプトを組んでみた。

概要

  • 地点名と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と異なり構造体を経由しない。以下の実装では次のようなことを行っている。
    • http.Getで得たres.Bodyを, 標準ライブラリのメソッドioutil.ReadAllで共通インターフェースである[]byte型に変換
    • オープンソースのgo-simplejsonを利用してjson型に変換
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)
}
  • CSV出力用のデータは,go-simplejsonのメソッドを利用することで得られる(参考)。
  • CSVへの出力は実装パターンAと同様。

おわりに

  • 構造体を宣言しない分,行数を圧縮できるので,go-simplejsonを利用する実装パターン2のほうが良いかもしれない。
  • とはいえ実装パターン1は,構造体のフィールドへのアクセスを利用してデータを操作するので,直感的に素早くコーティングできる利点も感じた。

補足と感想

  • 本記事を書き終わるタイミングで発見した記事。本記事と異なり「interface を利用して局所的に参照する」方法を紹介している。

qiita.com

  • こんな記事も見つけた。眺めるだけで面白そう。

qiita.com

  • Software Design5月号はGolang特集。CLIツール開発入門の記事もある。
    ソフトウェアデザイン 2019年5月号

    ソフトウェアデザイン 2019年5月号

    • 作者: 上田拓也,mattn,渋川よしき,鹿志村秀昭,曽利雅樹,舟窪恵一,向山優,安井正明,渡部敏雄,根本祐介,座間政紀,吉田英二,安藤幸央,結城浩,武内覚,宮原徹,平林純,くつなりょうすけ,中島明日香,上川慶,職業「戸倉彩」,中村壮一,田代勝也,山田泰宏,上田隆一,嶋是一,小飼弾,青田直大,あわしろいくや,中島雅弘,横田結菜,西谷友彬,大塚和彦,後藤大地,杉山貴章,Software Design編集部
    • 出版社/メーカー: 技術評論社
    • 発売日: 2019/04/18
    • メディア: 雑誌
    • この商品を含むブログを見る
  • Golangは変数や関数の宣言で細かく型を書く。そのため調べ物の際に読むソースコードがとても読みやすい。初心者にとってはありがたい。
  • 同じ機能のスクリプトを昨年Pythonで書いたので,良い復習になった。
    • ちなみにPythonでの実装では,requests, json, csvライブラリを利用。
  • 久しぶりにブログを書いたが,復習になるだけでなく,執筆の過程で付加的な情報が色々と集まってくる。
  • 少しずつレベルを上げつつ,色んなツールを今後開発したい。

React.js事始め

執筆の動機

React.jsを使用する仕事に初めてアサインされた。自分が仕事にキャッチアップする過程で学んだことを記録したい。今回は,キャッチアップの初期に学んだ概念を中心に紹介する。

React.jsとは

FacebookOSSとして公開しているUIを作るためのJavaScriptライブラリ。

React is a declarative, efficient, and flexible JavaScript library for building user interfaces. It lets you compose complex UIs from small and isolated pieces of code called “components”.

公式チュートリアル

React.jsはFacebookのほか,Nintendo SwitchTwitterNetflixなどの有名サービスでも使用されている。コンポーネント指向によるモジュール性の高さが採用の理由とのことである(参考

component

上の引用文にある通りReactではコンポーネントを作成し,それらを組み合わせることで,複雑なUIを表現する。 自分がアサインされた仕事のプロトタイピングでは,以下のディレクトリ構造でSPAの開発を行っている(一部抜粋)

components
└Layout.js
pages
├about.js
├index.js 
└item.js

Layout.jsでは,children, title='hoge', pageTitleを引数にとる無名関数がconst Layoutに代入されている。無名関数における処理として,ページのメタデータ,ページ上部のリンクと下部のフッターがJSX(後述)で記述されている。また,上部のリンクと下部のフッターの間には,{children}を包含している。それをLayoutコンポーネントとしてexportし,他のファイルから呼び出せるようにしている。

pagesディレクトリの各ファイルには,ページの本体が記述されており,Layoutコンポーネントを呼び出す。この結果,ページ上部のリンクと,本体,下部のフッターが合わさり,SPAとして描画される。

children 子要素をwrapするような子要素のこと(参考

JSXの記法

コンポーネントマークアップとロジックの双方を含んだ小さな塊である。一般にReactを用いた開発では,JavaScriptのExtensionであるJSXという記法を用いて,文章構造を記述する。

const element = <h1>Hello, world!</h1>;

This funny tag syntax is neither a string nor HTML. It is called JSX, and it is a syntax extension to JavaScript.

公式ドキュメント

Atomエディタでの開発環境

自分の開発環境には,パッケージlinter-js-standardが既にインストールされていた。そのまま開発に着手したが,JSXの記述部分についてSyntax Errorの通知が赤色で表示されてしまう。そこで,以下のパッケージをインストールした。

加えて,linter-js-standardをver6.0.0にアップデートし,Settingsで"Only lint if installed locally""Skip if ESLint is installed locally"にチェックを入れた。

f:id:ht-eightyeight:20180921232347p:plain

公式ページ以外の教材