Go言語で東京メトロAPIを叩く

東京メトロがWebAPIで色々な情報を提供しているようなので早速使ってみました。

[東京メトロ オープンデータ 開発者サイト](https://developer.tokyometroapp.jp/)
元々はコンテスト用に公開してたAPIがそのまま使えるようになったみたいですね。

# ユーザ登録

APIの利用にはユーザ登録が必要です。登録は無料です。
申請内容の確認から登録まで最大で2営業日ほどお時間を、とありましたが自分が登録した時は数分で完了しました。

# アクセストークンの取得

登録が完了したら1個デフォルトのアクセストークンが発行されていると思いますので、今回はそれを使ってアクセスしてみましょう。

ログインして「アクセストークンの確認・追加」から確認できます。

# いざデータ取得

今回は運行情報を取得してみます。
→ API仕様： [列車運行情報 odpt:TrainInformation](https://developer.tokyometroapp.jp/documents/railway#列車運行情報-odpt:TrainInformation)

```go:main.go
package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "strings"
    "time"
)

const (
    ENDPOINT     = "https://api.tokyometroapp.jp/api/v2/datapoints"
    CONSUMER_KEY = <your consumer key>
)

// レスポンスJSONデータ用構造体
type TrainInfomation struct {
    Context                string    `json:"@context"`
    Id                     string    `json:"@id"`
    Type                   string    `json:"@type"`
    Date                   time.Time `json:"dc:date"`
    Valid                  time.Time `json:"dct:valid"`
    Operator               string    `json:"odpt:operator"`
    TimeOfOrigin           time.Time `json:"odpt:timeOfOrigin"`
    Railway                string    `json:"odpt:railway"`
    TrainInformationStatus string    `json:"odpt:trainInformationStatus"`
    TrainInformationText   string    `json:"odpt:trainInformationText"`
}

// レスポンスJSONデータ配列
type TrainInformations []TrainInfomation

func main() {
  // URL生成
  q := map[string]string{
    "rdf:type": "odpt:TrainInformation", // TypeにTrainInformation(運行情報)を設定
    "acl:consumerKey": CONSUMER_KEY, // アクセストークン
  }
  url := fmt.Sprintf("%s?%s", ENDPOINT, buildQuery(q))
  // URLを叩いてデータを取得
  resp, err := http.Get(url)
  if err != nil {
    log.Fatal(err)
  }
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    log.Fatal(err)
  }
  // 取得したデータをJSONデコード
  var trains TrainInformations
  err = json.Unmarshal(body, &trains)
  if err != nil {
    log.Fatal(err)
  }
  // 取得したデータを整形して出力する
  for _, train := range trains {
    // 路線名
    railway := strings.Replace(train.Railway, "odpt.Railway:TokyoMetro.", "", -1)
    // 運行情報を組み立てる
    text := train.TrainInformationText
    if len(train.TrainInformationStatus) > 0 {
      text = fmt.Sprintf("%s (%s)", train.TrainInformationStatus, train.TrainInformationText)
    }
    fmt.Printf("%s: %s [%s]\n", railway, text, train.Date)
  }
}
func buildQuery(q map[string]string) string {
  queries := make([]string, 0)
  for k, v := range q {
    qq := fmt.Sprintf("%s=%s", k, v)
      queries = append(queries, qq)
  }
  return strings.Join(queries, "&")
}
```

```
Fukutoshin: 現在、平常どおり運転しています。 [2016-05-16 23:10:03 +0900 JST]
Hanzomon: 現在、平常どおり運転しています。 [2016-05-16 23:10:03 +0900 JST]
Hibiya: 現在、平常どおり運転しています。 [2016-05-16 23:10:03 +0900 JST]
Ginza: 現在、平常どおり運転しています。 [2016-05-16 23:10:03 +0900 JST]
Chiyoda: ダイヤ乱れ (21時23分頃、ＪＲ常磐線各駅停車内で地震のため、ダイヤが乱れ ています。只今、東京メトロ線、都営地下鉄線、ＪＲ線、東急線、東武線、京成線、小田急線、京王線、つくばエクスプレス線に振替輸送を実施しています。詳しくは、駅係員にお尋ねください。) [2016-05-16 23:10:03 +0900 JST]
Namboku: 現在、平常どおり運転しています。 [2016-05-16 23:10:03 +0900 JST]
Marunouchi: 現在、平常どおり運転しています。 [2016-05-16 23:10:03 +0900 JST]
Yurakucho: 現在、平常どおり運転しています。 [2016-05-16 23:10:03 +0900 JST]
Tozai: 現在、平常どおり運転しています。 [2016-05-16 23:10:03 +0900 JST]
```

こういうのをサクッと作れるのもGo言語の強みですね。
時間があったらAPIのラッパーライブラリを作ろうと思います。