ここがつらいよ東京公共交通オープンデータチャレンジAPI

2018/1/4修正：五月雨式に追記していたのを清書しました。以下2018/1/4時点での情報です

12/7から公共交通オープンデータ協議会主催で[東京公共交通オープンデータチャレンジ](https://tokyochallenge.odpt.org/)が開催されています。

これは東京メトロ発足10周年を記念して開催された[東京メトロオープンデータ活用コンテスト](http://awards.tokyometroapp.jp/)と同様に、各種公共交通機関の静的データ（一部動的データ）を広く公開しているものです。

既にQiitaでもいくつかこれに関するエントリーが挙がっていますが、ここではAndroidアプリ向けにAPIを触ってみた感想の中でも、事業者ごとの差異でつらかった点を書いてみます。

*下記のつらみを極力吸収した[Android向けのライブラリ](https://github.com/teracy/OdptLibrary)を作りました。*

# 全般

## とにかく不安定

API仕様ドキュメント・フォーラム・APIが同じサーバで運用されているのか、どれかが落ちているときはそれ以外もアクセスできないため開発の手を止めざるを得なくなります。ドキュメントだけでも手元に保存するのが吉です。

## optionalだからnullを入れるよ！

API仕様でoptionalとなっている項目にわざわざnullを明示的に入れて送信してくれる事業者があります。

下記の例は路線情報応答における路線コード・路線シンボル表記（odpt:lineCode）ですが、JR東日本左沢線では項目そのものが返ってこないのに対し、西武鉄道秩父線では明示的にnullが入っています。私はgsonでパースしているので特に影響はありませんが、環境によっては注意が必要かもしれません。

```json:JR東日本左沢線の路線情報応答（抜粋）
{"@id":"urn:ucode:_00001C00000000000001000003100DEC",
"@type":"odpt:Railway",
"dc:date":"2017-12-06T18:27:01+09:00",
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"dc:title":"左沢線",
"owl:sameAs":"odpt.Railway:JR-East.Aterazawa",
"odpt:operator":"odpt.Operator:JR-East",
"odpt:stationOrder":[
{"odpt:index":1,
"odpt:station":"odpt.Station:JR-East.Aterazawa.Yamagata",
"odpt:stationTitle":"山形"},

{"odpt:index":12,
"odpt:station":"odpt.Station:JR-East.Aterazawa.Aterazawa",
"odpt:stationTitle":"左沢"}]}
```

```json:西武鉄道秩父線の路線情報応答（抜粋）
{"@id":"urn:ucode:_00001C00000000000001000003100E56",
"@type":"odpt:Railway",
"dc:date":"2017-12-08T10:45:33+09:00",
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"dc:title":"西武秩父線",
"owl:sameAs":"odpt.Railway:Seibu.SeibuChichibu",
"odpt:lineCode":null,
"odpt:operator":"odpt.Operator:Seibu",
"odpt:stationOrder":[
{"odpt:index":1,
"odpt:station":"odpt.Station:Seibu.SeibuChichibu.Agano",
"odpt:stationTitle":"吾野"},

{"odpt:index":6,
"odpt:station":"odpt.Station:Seibu.SeibuChichibu.SeibuChichibu",
"odpt:stationTitle":"西武秩父"}]}
```

## いつになったらデータ提供してくれるの？

コンテストが始まってもうすぐ１か月ですが、まだデータを公開していない事業者が結構あります。

### APIの提供状況

（〇：提供中、×：提供予定（現時点で取得できない）、△：公式には予定となってるが現時点で取得可能、-：未提供）

鉄道API

|事業者|駅別乗降人員|鉄道路線情報|運賃情報|駅情報|駅時刻表|列車情報|列車運行情報|列車時刻表|
|:---|:---|:---|:---|:---|:---|:---|:---|:---|
|JR東日本|〇|〇|-|〇|×|〇|〇|〇|
|京急電鉄|-|〇|×|〇|×|-|×|×|
|京王電鉄|△|〇|-|〇|×|-|×|×|
|京成電鉄|△|〇|-|〇|-|-|-|-|
|小田急電鉄|×|〇|-|〇|-|-|×|-|
|西武鉄道|×|〇|×|〇|-|-|-|-|
|東武鉄道|△|〇|△|〇|×|-|-|-|
|都営|〇※1|〇|〇|〇|×|×|〇|〇|
|東京メトロ|△※2|〇|〇|〇|〇|〇|〇|〇|
|東急電鉄|△|〇|×|〇|-|-|×|-|
|東京臨海高速鉄道|×|〇※3|×|〇|×|-|×|×|
|ゆりかもめ|-|〇|△|〇|-|-|-|-|

* ※1 2018/1/4現在、都営地下鉄のみです。日暮里・舎人ライナーは今後追加される予定とのことです
* ※2 2018/1/4現在、事業者ID（odpt:operator）を指定すると取得できますが、路線ID（odpt:railway）や駅ID（odpt:station）を指定すると取得できません。またrequiredな情報（生成時刻など）が返ってこないため、実質的にまだ実装されていないと考えた方がよいです
* ※3 2018/1/4現在、路線ID（owl:sameAs）が誤っています

バスAPI

|事業者|バス情報|バス運賃情報|バス時刻表|バス路線情報|バス停標柱情報|バス停標柱時刻表|
|:---|:---|:---|:---|:---|:---|:--|
|JRバス関東|-|-|-|×|×|-|
|関東バス|-|-|×|×|×|-|
|京王バス|-|-|×|×|×|×|
|国際興業|-|-|×|×|×|-|
|西東京バス|-|×|×|×|×|-|
|小田急バス|-|-|〇|〇|〇|-|
|西武バス|-|-|〇|〇|〇|-|
|東武バス|-|-|×|×|×|-|
|都営|〇|〇|-|〇|〇|〇|
|東急バス|-|-|×|×|×|-|

航空機API

|事業者|空港発情報|空港着情報|空港時刻表|
|:---|:---|:---|:---|
|全日空|-|-|〇|
|成田国際空港|〇|〇|-|
|東京国際空港ターミナル|〇|〇|×|

## 鉄道API以外のドキュメントの質が…

鉄道API以外のドキュメントが粗削りです。他のAPIからコピペしたのか、結構誤っているものも多いです。

## 君の名は？

東京メトロオープンデータの時はAPIだけでは取得できないボキャブラリ（行き先や種別といったもののIDと自然言語の対応）の一覧が提供されていましたが、本コンテストでは今のところ提供されていません。従ってIDから自然言語に変換するには事業者の公式サイトを見るなりして類推するしかありません。

例：

 東京メトロ半蔵門線の方面ID：「odpt.RailDirection:TokyoMetro.Shibuya」
 →多分「渋谷方面」

JR東日本中央快速線の列車種別ID：「odpt.TrainType:JR-East:ChuoLimitedRapid」
→多分「中央特快」

小田急バスの吉０６系統の運行曜日・日付情報ID：「odpt.Calendar:Specific.OdakyuBus.Kichijouji.Weekday01」
→平日？？？

# 鉄道API

## 駅別乗降人員API

### 東武スカイツリーライン？伊勢崎線？

*2018/1/4現在、まだ公式には提供予定の状態なので、今後変わる可能性があります*

鉄道路線APIや駅情報APIでは東武スカイツリーラインに属している駅は駅別乗降人員で路線（odpt:railway）を指定する場合は伊勢崎線（odpt.Railway:Tobu.Isesaki）を指定する必要があります。

何が面倒かというと、駅別乗降人員APIは条件に路線ID（odpt:Railwayのowl:sameAs）や駅ID（odpt:Stationのowl:sameAs）を指定できますが、路線情報APIや駅情報APIで得られたIDを使うと駅別乗降人員APIでは取得できないという事です。

浅草～東武動物公園間が「東武スカイツリーライン」になったのは2012年ですので、少なくとも2013年以降のデータが伊勢崎線になっているのはおかしい気がします。

下記の例は東武スカイツリーライン浅草駅の各APIにおける情報です。

```json:東武スカイツリーライン浅草駅の駅別乗降人員情報
{"@id":"urn:ucode:_00001C000000000000010000030E6B89",
"@type":"odpt:PassengerSurvey",
"dc:date":"2016-06-24T15:11:18+09:00",
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"owl:sameAs":"odpt.PassengerSurvey:Tobu.Asakusa.2015",
"odpt:railway":["odpt.Railway:Tobu.Isesaki"],
"odpt:station":["odpt.Station:Tobu.Isesaki.Asakusa"],
"odpt:operator":"odpt.Operator:Tobu",
"odpt:surveyYear":2015,
"odpt:passengerJourneys":53190}
```

```json:東武スカイツリーライン浅草駅の駅情報
{"@id":"urn:ucode:_00001C00000000000001000003102BA4",
"@type":"odpt:Station",
"dc:date":"2017-12-08T13:40:52+09:00",
"geo:lat":35.712039,
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"dc:title":"浅草",
"geo:long":139.798474,
"owl:sameAs":"odpt.Station:Tobu.TobuSkytree.Asakusa",
"odpt:railway":"odpt.Railway:Tobu.TobuSkytree",
"odpt:operator":"odpt.Operator:Tobu",
"odpt:stationCode":"TS-01"}
```

```json:東武スカイツリーラインの路線情報に含まれる浅草駅
{"odpt:index":1,
"odpt:station":"odpt.Station:Tobu.TobuSkytree.Asakusa",
"odpt:stationTitle":"浅草"}
```

## 鉄道路線情報API

### 運行系統名（dc:title）のフォーマットが事業者によって違う

例えば路線名が「○○線」の場合、「○○線」で送られてくる事業者と「○○」で送られてくる事業者とがあります。前者は東京メトロと東京臨海高速鉄道で、それ以外は後者です。

末尾に「線」がなければ補ってやればよいかというと、「東武スカイツリーライン」や「東武アーバンパークライン」が存在するので罠があります。

### 都営のデータが怪しい

API仕様にはない「odpt:travelTime」という項目が存在します。

この項目は（今のところ）どのAPIで送られてくるか明示されていない状態で定義自体はありますが、その定義とも一部内容に矛盾があります。具体的には、「odpt:necessaryTime」が「分」で定義されているのに、明らかに「秒」が入っています。

下記の例は三田線目黒駅から白金台駅までのデータですが、流石に120分も掛からないと思います。

```json:三田線目黒駅と白金台駅
{"odpt:toStation":"odpt.Station:Toei.Mita.Shirokanedai",
"odpt:trainType":"odpt.TrainType:Local",
"odpt:fromStation":"odpt.Station:Toei.Mita.Meguro",
"odpt:necessaryTime":120}
```

### 京成電鉄の駅ナンバリングが独特

これはデータの不備というわけではありませんが、路線毎ではなく全線で連番を振っているため、番号が揃っていないので注意が必要です。

参考：[京成電鉄路線図（PDF）](http://www.keisei.co.jp/keisei/tetudou/railmap/railmap.pdf)

下記の例は金町線のデータの抜粋です。

```json:京成金町線
{"odpt:stationOrder":[
{"odpt:index":10,
"odpt:station":"odpt.Station:Keisei.Kanamachi.KeiseiTakasago",
"odpt:stationTitle":"京成高砂"},
{"odpt:index":50,
"odpt:station":"odpt.Station:Keisei.Kanamachi.Shibamata",
"odpt:stationTitle":"柴又"},
{"odpt:index":51,
"odpt:station":"odpt.Station:Keisei.Kanamachi.KeiseiKanamachi",
"odpt:stationTitle":"京成金町"}]}
```

京成高砂駅は京成本線で先に番号が振られているため、連番になっていません。

### データにtypoがある

#### 東京臨海高速鉄道りんかい線

現時点で路線情報APIに限り、東京臨海高速鉄道りんかい線の路線ID（owl:sameAs）が**「odpt.Railway:odpt.Station:TWR.Rinkai」**になっています。正しくは**「odpt.Railway:TWR.Rinkai」**のはずです。sameAsは他のAPIにアクセスするときの検索条件として利用するので注意が必要です。（駅情報APIは正しい路線IDで検索できました）

#### 小田急江ノ島線

小田急江ノ島線本鵠沼駅の「鵠」の字が化けてます。（ファイルに落としてもLogcatでも同様でした）
隣の鵠沼海岸駅の「鵠」の字は正しいので入力ミスでしょうか。

```json:小田急江ノ島線（抜粋）
[{"@id":"urn:ucode:_00001C00000000000001000003100E53",
"@type":"odpt:Railway",
"dc:date":"2017-12-08T10:51:28+09:00",
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"dc:title":"江ノ島線",
"owl:sameAs":"odpt.Railway:Odakyu.Enoshima",
"odpt:lineCode":"OE",
"odpt:operator":"odpt.Operator:Odakyu",
"odpt:stationOrder":[
{"odpt:index":1,
"odpt:station":"odpt.Station:Odakyu.Enoshima.HigashiRinkan",
"odpt:stationTitle":"東林間"},

{"odpt:station":"odpt.Station:Odakyu.Enoshima.HonKugenuma",
"odpt:stationTitle":"本沼"},
{"odpt:index":15,
"odpt:station":"odpt.Station:Odakyu.Enoshima.KugenumaKaigan",
"odpt:stationTitle":"鵠沼海岸"},
{"odpt:index":16,
"odpt:station":"odpt.Station:Odakyu.Enoshima.KataseEnoshima",
"odpt:stationTitle":"片瀬江ノ島"}]}]
```

## 運賃情報API

### 固有識別子別名（owl:sameAs）のフォーマット違反がある

仕様での命名ルールは**「odpt.RailwayFare:出発駅の会社名.出発駅の路線名.出発駅名.到着駅の会社名.到着駅の路線名.到着駅名」**ですが、
東京メトロ以外の事業者では**「odpt.RailwayFare:出発駅の会社名.出発駅の路線名.出発駅名.到着駅の路線名.到着駅名」**と、「到着駅の会社名」がありません。

下記の例は都営三田線三田駅から都営浅草線馬込駅のデータです。

```json:都営三田線三田駅発_都営浅草線馬込駅着
[{"@id":"urn:ucode:_00001C000000000000010000030E6CB2",
"@type":"odpt:RailwayFare",
"dc:date":"2016-06-08T16:33:18+09:00",
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"owl:sameAs":"odpt.RailwayFare:Toei.Mita.Mita.Asakusa.Magome",
"odpt:operator":"odpt.Operator:Toei",
"odpt:toStation":"odpt.Station:Toei.Asakusa.Magome",
"odpt:icCardFare":216,
"odpt:ticketFare":220,
"odpt:fromStation":"odpt.Station:Toei.Mita.Mita",
"odpt:childIcCardFare":108,
"odpt:childTicketFare":110}]
```

仕様に則っていれば「odpt.RailwayFare:Toei.Mita.Mita.Toei.Asakusa.Magome」のはずです。

### データにtypoがある

東武鉄道のサイトに則れば東上線大山駅が「odpt.Station:Tobu.Tojo.Oyama」のはずが、「odpt.Station:Tobu.Tojo.Uyama」になっている気がします。

参考：[大山駅 | 路線図・駅情報 | 東武鉄道](http://railway.tobu.co.jp/guide/station/info/7203.html)

```json:大山駅？
[{"@id":"urn:ucode:_00001C000000000000010000030EFFB4",
"@type":"odpt:RailwayFare",
"dc:date":"2016-12-12T17:53:50+09:00",
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"owl:sameAs":"odpt.RailwayFare:Tobu.Tojo.Uyama.Tojo.Wakoshi",
"odpt:operator":"odpt.Operator:Tobu",
"odpt:toStation":"odpt.Station:Tobu.Tojo.Wakoshi",
"odpt:icCardFare":195,
"odpt:ticketFare":200,
"odpt:fromStation":"odpt.Station:Tobu.Tojo.Uyama",
"odpt:childIcCardFare":97,
"odpt:childTicketFare":100}]
```

## 駅情報API

### 駅番号は適切？
京急本線泉岳寺駅の駅番号（odpt:stationCode）に「KK00」が入っていますが、京急電鉄の公式サイトに記載はありません。APIの引数としては使えますが、アプリでは表示しないほうがよいかもしれません。

```json:京急本線駅情報（泉岳寺駅・品川駅のみ抜粋）
[{"@id":"urn:ucode:_00001C000000000000010000031020ED",
"@type":"odpt:Station",
"dc:date":"2017-12-08T13:40:51+09:00",
"geo:lat":35.637928,
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"dc:title":"泉岳寺",
"geo:long":139.739046,
"owl:sameAs":"odpt.Station:Keikyu.Main.Sengakuji",
"odpt:railway":"odpt.Railway:Keikyu.Main",
"odpt:operator":"odpt.Operator:Keikyu",
"odpt:stationCode":"KK00"},
{"@id":"urn:ucode:_00001C000000000000010000031020EE",
"@type":"odpt:Station",
"dc:date":"2017-12-08T13:40:51+09:00",
"geo:lat":35.62824,
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"dc:title":"品川",
"geo:long":139.738018,
"owl:sameAs":"odpt.Station:Keikyu.Main.Shinagawa",
"odpt:railway":"odpt.Railway:Keikyu.Main",
"odpt:operator":"odpt.Operator:Keikyu",
"odpt:stationCode":"KK01"}]
```

参考：
* [泉岳寺駅 | 路線図・各駅情報 | 電車・駅・路線 | 【KEIKYU WEB】京急電鉄オフィシャルサイト](http://www.keikyu.co.jp/train-info/kakueki/A07.html) : 駅番号なし
* [品川駅 | 路線図・各駅情報 | 電車・駅・路線 | 【KEIKYU WEB】京急電鉄オフィシャルサイト](http://www.keikyu.co.jp/train-info/kakueki/KK01.html) : 駅番号あり

### データにtypoがある

路線情報同様に、小田急江ノ島線本鵠沼駅の「鵠」の字が化けてます。（ファイルに落としてもLogcatでも同様でした）

```json:小田急江ノ島線（本鵠沼駅・鵠沼海岸駅のみ抜粋）
[{"@id":"urn:ucode:_00001C00000000000001000003102AB9",
"@type":"odpt:Station",
"dc:date":"2017-12-08T13:40:51+09:00",
"geo:lat":35.330802,
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"dc:title":"本沼",
"geo:long":139.474915,
"owl:sameAs":"odpt.Station:Odakyu.Enoshima.HonKugenuma",
"odpt:railway":"odpt.Railway:Odakyu.Enoshima",
"odpt:operator":"odpt.Operator:Odakyu",
"odpt:stationCode":"OE14"}

{"@id":"urn:ucode:_00001C00000000000001000003102ABA",
"@type":"odpt:Station",
"dc:date":"2017-12-08T13:40:51+09:00",
"geo:lat":35.320702,
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"dc:title":"鵠沼海岸",
"geo:long":139.471088,
"owl:sameAs":"odpt.Station:Odakyu.Enoshima.KugenumaKaigan",
"odpt:railway":"odpt.Railway:Odakyu.Enoshima",
"odpt:operator":"odpt.Operator:Odakyu",
"odpt:stationCode":"OE15"}]
```

## 駅時刻表API

特に目立った綻びはないように感じました。

## 列車情報（列車ロケーション）API

現在取得可能なJR東日本と東京メトロの両方で、仕様にない項目が多く乗っている気がします。（odpt:○○Titleを除く）

まだ都営の情報が取れないので何とも言えませんが、事業者ごとに作り分けた方がいいかもしれません。（常磐緩行線と千代田線、三田線と南北線などが厄介そうですが）

```json:JR東日本の例
{"@id":"urn:uuid:e0e9e14f-2b64-4be4-913c-8dc8821e1442",
"@type":"odpt:Train",
"dc:date":"2017-12-15T15:47:34+09:00",
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"odpt:delay":0,
"odpt:index":2,
"owl:sameAs":"odpt.Train:JR-East.Takasaki.843M",
"odpt:railway":"odpt.Railway:JR-East.Takasaki",
"odpt:operator":"odpt.Operator:JR-East",
"odpt:toStation":"odpt.Station:JR-East.Takasaki.Urawa",
"odpt:fromStation":"odpt.Station:JR-East.Takasaki.Akabane",
"odpt:trainNumber":"843M",
"odpt:railDirection":"odpt.RailwayDirection:Outbound",
"odpt:carComposition":15,
"odpt:toStationTitle":"浦和",
"odpt:trainTypeTitle":"普通",
"odpt:fromStationTitle":"赤羽",
"odpt:destinationStation":"odpt.Station:JR-East.Takasaki.Kagohara"}
```

```json:東京メトロの例
{"@id":"urn:ucode:_00001C00000000000001000003101DF3",
"@type":"odpt:Train",
"dc:date":"2017-12-15T15:50:42+09:00",
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"dct:valid":"2017-12-15T15:51:12+09:00",
"odpt:delay":0,
"owl:sameAs":"odpt.Train:TokyoMetro.Ginza.A1551",
"odpt:railway":"odpt.Railway:TokyoMetro.Ginza",
"odpt:operator":"odpt.Operator:TokyoMetro",
"odpt:frequency":30,
"odpt:toStation":null,
"odpt:trainType":"odpt.TrainType:TokyoMetro.Local",
"odpt:trainOwner":"odpt.TrainOwner:TokyoMetro",
"odpt:fromStation":"odpt.Station:TokyoMetro.Ginza.Asakusa",
"odpt:trainNumber":"A1551",
"odpt:railDirection":"odpt.RailDirection:TokyoMetro.Shibuya",
"odpt:startingStation":"odpt.Station:TokyoMetro.Ginza.Asakusa",
"odpt:terminalStation":"odpt.Station:TokyoMetro.Ginza.Shibuya"}
```

### 固有識別子は指定できる？できない？

応答情報に固有識別子（owl:sameAs）が含まれているのでリクエスト引数に用いることが可能なはずですが、API仕様書では定義されていません。実際に引数に渡したところデータが取得できました。（ただし、対象の列車が在線していない場合は取得できません）

## 列車運行情報API

### 各社によって全く挙動が異なる

これが本当に困りもので、昨日までに取得できたJR東日本・都営・東京メトロで全く挙動が変わります。

|事業者|平常運行の路線のデータ|運行支障のある路線のデータ|
|:---|:---|:---|
|JR東日本|取れない|当日分の履歴含め古い順から全件|
|都営|最新1件のみ|取れない|
|東京メトロ|最新1件のみ|最新1件のみ|

東京メトロのオープンデータAPIと同じだと思っていると痛い目を見ます。

### JR東日本の場合

路線毎に、当日支障が生じていれば履歴情報含め1件以上のデータが返されます。つまり路線毎に以下のように判断します。

* 1件もデータがない場合、当日は全く運行に支障がない。つまり現時点でも運行に支障は生じていない
* 1件以上データがある場合、発生時刻（odpt:timeOfOrigin）が最も新しいデータを見て、現時点で運行に支障が生じているか判断するしかない

また、JR東日本の場合は発生場所等駅IDを引く項目がなく、代わりに駅名で返ってくることにも注意が必要です。

更に列車運行情報APIに限り、進行方面ID（odpt:railDirectionのフォーマットが仕様で定められた**「odpt:RailDirection:方面名」**ではなく**「odpt:RailwayDirection:方面名」**になっていることに注意が必要です。

### 東京メトロの場合

路線毎に、現時点で運行に支障があろうとなかろうと必ず1件のデータが取得できるため、路線毎に以下のように判断します。

* データに運行情報（odpt:trainInformationStatus）が存在しない場合、現時点で運行に支障は生じていない
* データに運行情報が存在する場合、現時点で運行に支障が生じている

### 都営の場合

路線毎に、現時点で運行に支障がなければ運行情報（odpt:trainInformationStatus）が存在しないデータが最新1件返ってきますが、運行に支障がある場合はデータそのものが送信されません。従って路線毎に以下のように判断します。

* データが存在する場合、現時点で運行に支障は生じていない
* データが存在しない場合、現時点で運行に支障が生じている。ただし詳細情報は分からない

また都営の場合、API仕様上でrequiredである発生時刻（odpt:timeOfOrigin）が存在しないことにも注意が必要です。（まあ、そもそも運行に支障が生じているとデータそのものが返ってこないので意味がないですが）

## 列車時刻表API

### JR東日本の場合に終着駅かの判断に悩む

現時点で取得できるJR東日本・都営・東京メトロで、それぞれ微妙にフォーマットが違います。ただし、仕様から大きく逸脱しているわけではないのでそれほど気になるものではありません。

それよりも気になるのが、列車時刻表データ（odpt:trainTimetableObject）において、JR東日本の場合に終着駅かどうか判断できないデータがある事です。

```json:JR東日本常磐緩行線1247E列車（平日）の抜粋
[{"@id":"urn:ucode:_00001C00000000000001000003107EA8",
"@type":"odpt:TrainTimetable",
"dc:date":"2017-12-07T23:43:47+09:00",
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"owl:sameAs":"odpt.TrainTimetable:JR-East.JobanLocal.1247E.Weekday",
"odpt:railway":"odpt.Railway:JR-East.JobanLocal",
"odpt:calendar":"odpt.Calendar:Weekday",
"odpt:operator":"odpt.Operator:JR-East",
"odpt:trainType":"odpt.TrainType:JR-East:Local",
"odpt:trainNumber":"1247E",
"odpt:railDirection":"odpt.RailDirection:Outbound",
"odpt:trainTimetableObject":[
	{"odpt:index":1,
	"odpt:departureTime":"14:01",
	"odpt:departureStation":"odpt.Station:JR-East.JobanLocal.Ayase"},
	{"odpt:index":2,
	"odpt:departureTime":"14:03",
	"odpt:departureStation":"odpt.Station:JR-East.JobanLocal.Kameari"},
	
	{"odpt:index":11,
	"odpt:departureTime":"14:27",
	"odpt:departureStation":"odpt.Station:JR-East.JobanLocal.KitaKashiwa"},
	{"odpt:index":12,
	"odpt:departureTime":"14:30",
	"odpt:departureStation":"odpt.Station:JR-East.JobanLocal.Abiko"}
]}]
```
終着駅のデータに存在すべき到着時間（odpt:arrivalTime）や到着駅駅ID（odpt:arrivalStation）がなく、逆に終着駅のデータに存在しないはずの出発時間（odpt:departureTime）や出発駅駅ID（odpt:departureStation）があります。

仕様ではこれらの有無で始発駅・終着駅・途中停車駅の区別を判断せよとあるので困ったことになります。この列車は我孫子から成田線に乗り入れするのかな？と思いましたが、[常磐線1247E列車の行き先は我孫子](http://www.jreast-timetable.jp/1712/train/145/145491.html)なので、そういう事でもないようです。

JR東日本でも到着時間や到着駅駅IDのあるデータもあったため、JR東日本の場合は仕様にない「odpt:index」を使って、もっとも大きければ終着駅と判断するのがよいのかもしれません。

同じJR東日本でも終着駅が判断できるデータの例を下記に示します。

```json:JR東日本中央快速線1306T列車（平日）の抜粋
[{"@id":"urn:ucode:_00001C000000000000010000031096B6",
"@type":"odpt:TrainTimetable",
"dc:date":"2017-12-07T23:43:49+09:00",
"@context":"http://vocab.odpt.org/context_odpt.jsonld",
"owl:sameAs":"odpt.TrainTimetable:JR-East.ChuoRapid.1306T.Weekday",
"odpt:railway":"odpt.Railway:JR-East.ChuoRapid",
"odpt:calendar":"odpt.Calendar:Weekday",
"odpt:operator":"odpt.Operator:JR-East",
"odpt:trainType":"odpt.TrainType:JR-East:ChuoLimitedRapid",
"odpt:trainNumber":"1306T",
"odpt:railDirection":"odpt.RailDirection:Inbound",
"odpt:trainTimetableObject":[
	{"odpt:index":1,
	"odpt:departureTime":"13:30",
	"odpt:departureStation":"odpt.Station:JR-East.ChuoRapid.Takao"},
	{"odpt:index":2,
	"odpt:departureTime":"13:33",
	"odpt:departureStation":"odpt.Station:JR-East.ChuoRapid.NishiHachioji"},

	{"odpt:index":13,
	"odpt:departureTime":"14:26",
	"odpt:departureStation":"odpt.Station:JR-East.ChuoRapid.Kanda"},
	{"odpt:index":14,
	"odpt:arrivalTime":"14:28",
	"odpt:arrivalStation":"odpt.Station:JR-East.ChuoRapid.Tokyo"
}]}]
```

# バスAPI

## 全般

### 小田急バスの日付時刻フォーマットが異なる

基本的に鉄道系APIも含め、日付時刻フォーマットを要求されている項目は[ISO_OFFSET_DATE_TIMEフォーマット](https://docs.oracle.com/javase/jp/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_OFFSET_DATE_TIME)（例："2017-12-13T15:52:57+09:00"）で返ってきますが、現時点で小田急バスのデータ保証期限（dct:valid）のみ[ISO_DATEフォーマット](https://docs.oracle.com/javase/jp/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_DATE)（例："2018-01-15"）で返ってきます。日付時刻型にパースする時に痛い目を見ました。

## バス情報（バスロケーション情報）API

特に目立った綻びはないように感じました。

## バス運行路線情報

odpt:busstopPoleOrderの停留所通過順（odpt:index）が0から始まる事業者と1から始まる事業者が存在しますが、リクエストに与える情報ではないのであまり気にすることはないでしょう。

## バス運賃情報API

### :poop::poop::poop::poop::poop::poop::poop::poop:

使うべきではないと思います。どうせ均一区間の多い都営しか使えませんし。

## バス停標柱情報API
  
特に目立った綻びはないように感じました。
  
## バス停標柱時刻表API
  
バス停標柱時刻表時分情報情報リストがAPI仕様書では「odpt:busstopTimetableObject」で定義されていますが、実際のJSONでは「odpt:busstopPoleTimetableObject」で返ってきます。命名ルール的にもデータが正、仕様書が偽と思われます。

## バス時刻表API

バス時刻表時分情報（odpt:busstopPoleOrder）の標柱通過順（odpt:index）が0から始まる事業者と1から始まる事業者が存在しますが、リクエストに与える情報ではないのであまり気にすることはないでしょう。

### 事業者IDはrequired？optional？

仕様書では事業者ID（odpt:operator）がrequiredになっていますが、固有識別子（owl:sameAs）を指定する場合は不要なはずです。実際に固有識別子を指定した場合は事業者IDなしでもデータが取得できます。

# 航空機API

正直、論評もしたくないレベルで酷い:poop:です。したがって、APIそれぞれのコメントは特に載せません。成田国際空港以外の事業者は仕様を守る気がないんでしょうか？

実装するなら全日空・東京国際空港ターミナル・成田国際空港それぞれ別で作った方が苦労がなくてよいと思います。