2015年5月27日水曜日

東京メトロAPIをC#で使う

お久しぶりです。
ちょっと最近いろいろと忙しくて、なかなかブログを書いている暇がありませんでした。プログラミングはちょくちょくやっていましたが。

ここ最近はまっているのは、表題の通り東京メトロのAPIです。

https://developer.tokyometroapp.jp/

昨年の9月に東京メトロは、駅情報や列車の運行情報、在線情報などを提供するためのAPIを公開しました。この時は、コンテストに参加する目的で利用が可能でしたが、そのコンテストが終わった後、今年4月から特にそういった目的でもなくAPIが使えるようになりました。
上記の東京メトロの開発者向けサイトに行き、必要な情報を入力してアカウントを取得することでAPIにアクセスするためのアクセストークンを入手することができます。

https://developer.tokyometroapp.jp/app

こちらにはコンテストに参加したアプリケーションや、コンテスト終了後に登録されたアプリケーションなど、様々なアプリケーションがあります。
最近流行りなのはやはりスマホアプリということで、コンテストでもスマホアプリに限定して募集されていましたし、その後もそういったアプリケーションの登録が非常に多いように見受けられます。
その中で、こんなアプリケーションがありました。

Tokyometro4J

東京メトロAPIのJavaラッパーです。

ん?じゃあこれは.NETラッパーを作るしかないな?

というわけで、作ってみました。

TokyoMetro.NET ver.1.0.0

ゆうて、やることはそんなに大変じゃないです。
URLにクエリとアクセストークンを入れてアクセスしたら、それに応じた各種情報をJSONで返してくれるだけです。なので、JSONを適宜パースして、適当なクラスに入れてやればいいだけです。JSONのパースもJson.NETに投げちゃいましたから、実質、ラッパークラスの実装とURLの作成がほとんどですかね。
それをやるだけなんですが、まあいろいろなデータがあるので、それぞれにおいてラッパークラスを実装してやるのは結構面倒でした。あと、最近流行りの非同期処理です。これを実現するために、2倍のメソッドの実装が必要でした。○○Asyncっていうメソッドを実装してやらなきゃいけないですからね…。

上記のライブラリ、例によってデモソフトとしてライブラリを使ったフロントエンドも同梱しています。普通にライブラリを使う分には何も問題無いですが、「とりあえずデモソフト立ち上げよう」と思った方、ごめんなさい。デモソフトはダウンロードしてそのままコンパイルするだけじゃ動きません。動くようにするためには然るべき場所にアクセストークンを入力し、コンパイルする必要があります。
アクセストークンは他人に漏らすわけにはいかないですし、.NETに関してはこんなソフトなどを使えば超簡単に逆コンパイルができてしまいます。オープンソースではもちろんのこと、難読化しない限り、なかなかこういうソフトをexeファイルですら公開しにくいんですよね。
難読化ソフトも無料のものではなかなか最新の.NETバージョンに対応していなかったり、そもそも文字列の難読化に対応していなかったりして使い物になりません。有料のは手を出すのがなかなか大変ですよね。

というわけで、自分で何かソフトを開発する方はもちろん、デモソフトを動かしてみたいと思った方でも東京メトロに開発者登録をして使うようにしてください。ごめんなさい。でもご理解の程お願いいたします。


さて、このライブラリは多分全部のAPIを網羅しています。見落としがあったらごめんなさい。
使い方はとても簡単で、

var api = new TokyoMetroApi("Consumer Key");

このようにTokyoMetroApiクラスのコンストラクタにアクセストークンを与えてインスタンス化するだけで準備は完了です。あとは、Search○○DatapointAsync()みたいな名前のメソッドを呼ぶだけで大体のデータは読み出せます。これらのメソッドは条件を指定することができて、例えば

var fukutoshin = (await api.SearchRailwayDatapointAsync(SameAs: IDs.Railway.TokyoMetro.Fukutoshin)).Single();

のように名前付き引数で条件を指定することで、この場合は副都心線のみの路線情報を取得しています。例えばRailwayFareなんかは条件を何も指定しないとあらゆる2駅間の組み合わせ(多分)の運賃が返ってくるので、サーバーにもクライアントにもネットワークにも大きな負荷を掛けることになってしまいます。必要十分なデータのみを読み出すことで、サーバーへの負荷を抑えましょう。
一応、こういった条件指定も少しだけできるので、LINQ to TokyoMetroとか実装できれば面白そうだなーって思ったりもしましたが、そもそもLINQの実装の話はあまり詳しくなかったり、LINQレベルでwhereが詳細に指定でいるわけでもないので、今回は見送りました。

ちなみに、非同期メソッドは末尾にAsyncが付いていて、付いていない場合は同期的に実行されます。ウェブアクセスが絡むメソッドは全部Asyncの有りバージョンと無しバージョンの2種類を実装しているはずですので、目的に合わせて使い分けてください。

それでは、各データのクラスの代表として、駅データを見てみましょう。

public class Station : ResponseBase
{
    internal Station(InternalStation Source) : base(new UCode(Source.Id))
    {
        //省略
    }

    public DateTime Date { get; private set; }

    public ID SameAs { get; private set; }

    public string Title { get; private set; }

    public string Region { get; private set; }

    public ID Operator { get; private set; }

    public ID Railway { get; private set; }

    public ReadOnlyCollection<ID> ConnectingRailway { get; private set; }

    public ID Facility { get; private set; }

    public ReadOnlyCollection<ID> PassengerSurvey { get; private set; }

    public string StationCode { get; private set; }

    public ReadOnlyCollection<UCode> Exit { get; private set; }

    public Coordinate Coordinate { get; private set; }

    public override string ToString()
    {
        return string.Format("{0} ({1})", string.IsNullOrEmpty(Title) ? string.Empty : Title, Railway == null ? string.Empty : Railway.Title);
    }
}

例えば、Stationクラスにはこのように幾つかIDクラスのプロパティが含まれています。これは、例えば"odpt.Railway:TokyoMetro.Ginza"などの文字列で定義されるIDが含まれています。
そっくりそのままこれをSearchRailwayDatapointAsync()メソッドのSameAs引数にセットして呼び出せば路線情報を引っ張り出せます。また、主要なIDはIDsクラスの中に固定データとして入れてありますので、そこから使うと良いでしょう。また、IDクラスはコンストラクタを持っておらず、ID.CreateOrGet()メソッドを通してインスタンス化する必要があります。シングルトン(と言っていいのかわかりませんが)のためですね。

Railwayとかその他のクラスに関してはVSのオブジェクトブラウザーでクラス一覧を見るなり何なりして使ってもらえればいいかと思います。

ちなみに、東京メトロAPIにはエラッタが多数あります。
コンテストに使われていた関係で、終盤にはAPIのエラッタを修正すると逆にアプリに問題を与えてしまう可能性があるので(コンテスト期間中はアプリのアップデートは禁止されていた)、不合理な仕様や単なるスペルミスやデータミスでもエラッタに放り込んで修正をしなかった背景があるようです。
これに関しては、私のライブラリではまあ最終的にはエラッタに相当するデータは修正した上で提供すると言うスタンスで設計しようかと思っておりますが、手を抜いて全部のエラッタを実装していません。と言うよりか、丸ノ内線支線にかかわるエラッタとスペルミス周辺しか修正していなかったと思います。ごめんなさい。
いやいや、アプリのコンテスト期間が過ぎたのでそろそろ東京メトロさんにはエラッタを直していただきたく…

とまあ、このへんがこのライブラリの概要です。
そうして、このライブラリを駆使して駅の緯度経度や列車の位置情報を求めて、リアルタイムに表示させるソフトを作りました。それがデモソフトです。デモソフトを眺めている様子を早回ししたものが下記の動画のようになります。



この日はたまたま14時半頃に東京で震度4の地震があって、緊急地震速報で全列車が停車する様子が見られました。面白いですね。
あ、別にデモソフトを使ったからってこういう動画が撮れるようになるわけじゃないです。これはあくまでもこのソフトを使って現在位置や運転情報が見られるよ~っていう様子を動画で示しただけなので…。