Web APIの使い方を森見登美彦風に覚える。

この記事は、[リンク情報システム](https://www.lis.co.jp/)が主催するイベント「[2021新春アドベントカレンダー Tech Connect](https://qiita.com/dgkz/private/eabde6515457d8acec9b)」のリレー記事です。
engineer.hanzomon のグループメンバによってリレーされます。
 （リンク情報システムのFaceBookは[こちら](https://ja-jp.facebook.com/lis.co.jp/)から）

最終日らしいです。頑張ります。
こんな記事が最終日で大丈夫か。
***

〇
　色々な点で、私は根本的に間違っている。
何故ならQiitaはこのような文章を投稿する場所ではないからだ。
〇

# やる気短し覚えよAPI

　業務上、長らくC#でのWindowsアプリを作成していた。業務で作成したアプリたちは未だインターネットの海を航行したことはなかった。そしてこれから作るアプリもまた、インターネット海に出航することはないだろう。
このままでは時代に取り残される。危機感を覚えた私は「今のうちにWeb APIなるものを使えるよう練習がしたい」と思い、自宅PCのVisual Studioを起動したのであった。

　常々、何か面白い事をしようと思い立った時、新しい技術の知識/経験に乏しく、何もできないが故に何も思いつかない。そのまま惰眠で時間をじゃぶじゃぶと浪費し、気持ちが急速に失われていくことがある。これを私はやる気殺人と名付けた。
やる気の連続殺人による治安低下で不安がっている私の脳内市民たちに、Web APIを習得することで安心してもらいたいというのが今回の目的である。

　「今更Web APIかよ」「未だに.Net Framework使っている時点で、お前は時代に取り残されてるわ」等の指摘は、私も痛いほど理解しているため控えていただくよう願う。

# 選定の技術
1月9日
　皆さんお元気だろうか。私は部屋がとても寒いので電気ヒーターの前から動けない中、この手紙を書いている。

　さてWeb APIの件でごちゃごちゃと喚いていた私だが、この度使用するWeb APIをついに決定した。
[**「駅すぱあとWebサービス」**](https://ekiworld.net/service/sier/webservice/free_provision.html)だ。無料で使え、結果が分かりやすく、今回の目的にぴったりではなかろうか。

　今までWeb APIを使ってこなかったため、Web APIを使用するのにWeb申し込みが必要だということを知らなかった。今日申し込んだばかりで、使えるようになるのに数日かかるのは痛い。さらに「コイツはそんなことも知らなかったのか」という皆の目線が突き刺さるのも痛い。しょうがないではないか。

　APIが使えるその日までにやる気が殺されてないといいが、この駄文を書き切らないと後々「Qiita記事書く書く詐欺野郎」という不名誉な称号が付されるため、何が何でも書かなければならない。やる気を生かすか、ゾンビとして復活させるかのどちらかしか、私に道はないのだ。

　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　草々   following_ng
記事を読んでくださる皆さんへ

# 製造の項
**1月10日**
　日付が変わると共に手紙を書き終えた私は、いつになるかわからないAPIの使用開始時期に不安を覚えつつ、C#でGUIを作ることにした。
[**「駅すぱあとWebサービス」のAPI設計書**](https://docs.ekispert.com/v1/api/)を見ながら、GUI側でやるべきことを列挙すると以下となる。

- 出発日時を指定する。起動時には現在時刻を表示する。
- 駅名をあいまい入力し、そこから候補駅をリスト表示する。
- リストから出発駅、到着駅を選択し、経路探索ボタンを押下することで経路を表示する。

今回はWeb APIを使用できればそれでいいので、上記のような仕様で勘弁願いたい。上記を実現したのが以下である。
![モック画面.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317702/2e876558-3e49-f29a-8eca-3fb47264e771.png)
こののっぺりしたGUIを作成し終えた私は、冷たい布団に倒れこみ翌朝まで泥の様に眠るのであった。

**1月11日**
　昨日、深夜のテンションで書き始めた駄文を読み返し、自分の文才のなさに泣きながら、少しでも奇天烈かつ面白みのある文章にしてやろうと推敲を始めた。しかしいくら時間が経っても駄文は駄文のままなので、私は私を呪った。

**1月12日**
　APIキーが送られてきた。これで開発の続きができる。Web開発原理主義者に「あいつ逃げやがったぜ」と笑いながら指をさされることは、今のところ回避できそうだ。しかし平日は業務多忙であるため開発作業及び駄文製造は週末に回したいと思う。

**1月15日**
　さて、この「駅すぱあとWebサービス」ではHTTPを使用してメッセージを送り、XMLもしくはJSON形式でデータの受け取りを行う。XMLとJSON、どちらも不慣れな私は「名前が強そう」という小学生のような理由で、XMLを使用することに決めた。

　兎にも角にもソースを書かなければアプリは出来上がらない。Web  APIを動作させるためGoogle検索エン神に祈りを捧げ情報収集し、以下のようなクラスを作成した。

```c#
    public class ApiCtrl
    {
        private String ApiAddress = String.Empty;
        public ApiCtrl(String Address)
        {
            //基本アドレス
            ApiAddress = Address;
        }
        public XElement GetResponse(String Code)
        {
            WebRequest request = WebRequest.Create(ApiAddress + Code);
            Stream response_stream = request.GetResponse().GetResponseStream();
            XElement xml = XElement.Load(response_stream);
            return xml;
        }
    }
```

作成してみると意外にシンプルな作りで拍子抜けした。こんなものでWeb APIが動くのか。私はこれから始まる”Web APIとの輝かしい未来”を思い描きつつ作業を進めた。
　続いて上記で作成したWeb API操作クラスを画面から使用するため、以下のようなメソッドを作成した。こちらも中々すっきり書くことができた。誠に申し訳ないが呼び出している変数や画面パーツの内容は変数名で想像してほしい。

```c#
private String StationSearchCode = "v1/xml/station/light?key={0}&name={1}&type=train";
private XElement GetStationInfo(String Name)
{
    XElement xml = null;

    //制御コード作成
    String Code = String.Format(StationSearchCode, AccessKey, Name);
    //WebAPIに指示
    xml = api.GetResponse(Code);

    return xml;
}

private String RouteSearchCode = "v1/xml/search/course?key={0}&from={1}&to={2}&date={3}&time={4}";
private XElement GetRouteInfo(String FromStation, String ToStation, DateTime SearchDatetime)
{
    XElement xml = null;
    //制御コード作成
    String Code = String.Format(RouteSearchCode, AccessKey, FromStation, ToStation, 
                                SearchDatetime.ToString("yyyyMMdd"), SearchDatetime.ToString("HHmm"));
    //WebAPIに指示
    xml = api.GetResponse(Code);

    return xml;
}
```

　ここまで来れば後は適当にXMLを読み取り、適当に画面表示を行えば目的は達成できる。ああWeb API、君はなんて単純なやつなんだ。
　私の勝ち誇った顔は、その後自らが犯した過ちによって曇っていくことを、予感させないほど光り輝いていた。この頃に戻って「正気に戻れ」と二三発ほど頬を打ってやりたい気持ちになるが、頬を打ったところで私が無能であることには変わりはない。

# 【新釈】動けアプリ バグ数件

　駅情報検索部を作成したが例外が発生し、アプリが途中で終了した。私は頭を抱えた。強そうな名前という理由で選んだXMLは、貧弱な私の手に負えるものではなかったのだ。おのれXML、ゴールを見据えた私の眼前に立ちはだかるとはいい度胸だ。

　以下のコードでXElement型のinfoは私が要素名を指定すると、その要素名に設定された値を返してくれるはずであった。ところが奴は要素名を聞いたところで、当たり前のような顔でNullReferenceExceptionを投げつけてくるのである。これは私に対しての宣戦布告に近しいものであった。

```c#
//コマンドを作成し、Web APIにコマンドを送信する。
XElement element = GetStationInfo(Station);

IEnumerable<XElement> infos = from item in element.Elements("Point") select item;

FromStationInfoList.Clear();
FromListBox.Items.Clear();
foreach (XElement info in infos)
{
    String Name = info.Element("Name").Value; // ここで例外発生
    String Code = info.Attribute("code").Value;

    FromStationInfoList.Add(new StationInfo(Name, Code));
    FromListBox.Items.Add(Name);
}
```
　色々試していると唯々私が阿呆だったということが明らかになっていく。`from item in element.Elements("Point") select item;`で、Point中の全ての要素に対し、名前を指定すれば値を返してくれるようになると私は勘違いしていた。それを受けてアプリは「Point中にNameなんて名前の要素はありません」と例外を投げつけてくるのである。考えてみれば至極当たり前のことである。
　`Name = info.Element("Name").Value; `を`Name = info.Element("Station").Element("Name").Value;`と書くことによって、この問題は解決したのであった。XMLよ、申し訳ない。私が愚かなばかりにお前にいらぬ罪を着せるところだった。

　今度は要の経路探索部で、例外が発生した。今度はWeb APIのエラー応答による例外であった。試しにブラウザで送ったURIを打ち込みアクセスしてみると以下のようなエラーが表示された。

```xml
<ResultSet apiVersion="1.27.0.0" engineVersion="">
    <Error code="W403">
        <Message>
            利用できない機能を呼び出しています。アクセスできる機能は、/corporation,/operationLine,/rail,/search/course/light,/station,/station/info,/station/lightです。
        </Message>
    </Error>
</ResultSet>
```

　私が使用しているプランは、APIフリープランであるため、機能制約があるらしい。何かしらの記事を書かねばと躍起になっていた私は、APIのプラン説明をちゃんと読んでいなかった。誰も責めることはできまい。
　エラー内容を読んでみると経路探索に使えそうな機能は`/search/course/light`くらいである。しかしAPI設計書を探しても`/search/course/light`の説明はなかった。試しに`/search/course/`としていたところを`/search/course/light`に書き換えて実行すると、エラーは出なくなった。これでやっとゴールにたどり着けると思った私にさらなる試練が待ち受けていたのであった。

　以下が経路探索の結果を示すXMLである。乗る路線や時間、経由地などが記されたXMLが返ってくると思っていた私は目を疑った。なんと[**Webページで検索した際の結果ページ**](https://roote.ekispert.net/result?arr=%E6%9D%B1%E4%BA%AC&arr_code=22828&connect=true&dep=%E6%96%B0%E5%AE%BF&dep_code=22741&express=true&highway=true&hour=1&liner=true&local=true&minute=52&plane=true&shinkansen=true&ship=true&sleep=false&sort=time&surcharge=3&type=dep&via1=&via1_code=&via2=&via2_code=&yyyymmdd=20210116)のURLを返却してきたのである。これではアプリ上に結果を表示することができないではないか。私は膝から崩れ落ちた。

```xml
<ResultSet apiVersion="1.27.0.0" engineVersion="202101_02a">
    <ResourceURI>
        https://roote.ekispert.net/result?arr=%E6%9D%B1%E4%BA%AC&arr_code=22828&connect=true&dep=%E6%96%B0%E5%AE%BF&dep_code=22741&express=true&highway=true&hour=1&liner=true&local=true&minute=52&plane=true&shinkansen=true&ship=true&sleep=false&sort=time&surcharge=3&type=dep&via1=&via1_code=&via2=&via2_code=&yyyymmdd=20210116
    </ResourceURI>
</ResultSet>
```

　私を崖下に突き落とし「ざまぁみろ。」と言わんばかりに、駅すぱあとWebサービスが私を指を刺して笑う妄想が私の頭の中を駆け巡った。”Web APIとの輝かしい未来”とは何だったのか。

　そんなことをぐちゃぐちゃと考えていてもオチがつかないので、どうにか形になるよう私はGoogle検索エン神に祈りと検索文字列を捧げエンターキーを押した。

# 四畳半結果発表
　C#もとい.Net Frameworkは私を見放したりはしなかった。Windows.FormsのパーツにWebBrowserというWebページを表示させるための画面パーツが存在したのだ。これで私は結果の画面表示ができるぞ。ありがとう.Net、ありがとうMicrosoft。

　WebBrowserを実装した画面が以下である。多少アプリの見た目が不格好になってしまったが、そんなことはもう気にしてなどいない。

![モック画面その2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317702/a956d195-55ce-be2b-3bc6-945ce28a9143.png)

　早速各機能を使用して経路探索を行ってみると以下の様に表示された。

![結果表示.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317702/8b928d79-9a5a-7d0a-7e79-49d6092a1d47.png)


　正しく経路探索が行われていることを確認した。この苦しく長い戦いに終止符が打たれたのであった。

〇
　私とWeb APIの関係がその後いかなる展開を見せたのか、それはこの稿の趣旨から逸脱する。したがって、その妙味を逐一書くことはさし控えたい。皆さんもそんな唾棄すべきものを読んで、貴重な時間を溝に捨てたくはないだろう。
　成功した開発ほど語るに値しないものはない。
〇

# 森見登美彦先生 大変申し訳ございませんでした。
　今回Qiitaに投稿する事柄を決めかねた私は、あろうことか好きな作家の書きっぷりを真似て、雑魚技術の習得を大層立派なことをしたかのように書くという過ちを犯しました。

**森見登美彦先生 及び 森見登美彦ファンの皆様 誠に申し訳ありません。**

次は米澤穂信先生で書きたいですが、もう疲れたので無理です。
あとアドベントカレンダーはこれで終了です。お疲れ様でした。


***

[リンク情報システム株式会社](https://www.lis.co.jp/)では一緒に働く仲間を[随時募集](https://www.lis.co.jp/employ_top)しています！
 また、お仕事のご依頼、ビジネスパートナー様も募集しております。[お気軽にご連絡](https://www.lis.co.jp/inquiry)ください。