乗換案内オープンAPIをアプリでも使う

※所属団体とは無関係の立場で書く記事になります。
※一部問題があったため、一度再アップしています。

![スクリーンショット 2018-07-12 13.52.32.png](https://qiita-image-store.s3.amazonaws.com/0/114168/d46f7f1a-43aa-4df5-0396-fe2e3385199c.png)
[乗換案内オープンAPI](https://norikae.jorudan.co.jp/openapi/)

つい先日から乗換案内オープンAPIというサービスが開始されました。何が出来るかというと、鉄道の経路検索を1経路だけ無料で取得することが出来ます。そんなAPIです。

#乗換案内オープンAPIで、何が出来るのか？
大きく下記の5つのことができます。

- 任意のキーワードからの駅名検索
- 任意のキーワードからの路線名検索
- 特定の駅を通る路線の一覧取得
- 特定の路線に所属する全ての駅を取得
- 経路検索機能

某研究所が公開されている、ほにゃららWebサービスとの大きな違いは、経路検索結果をURLとして取得するのではなく、細かな経路情報をJSON形式で取得出来るということです。

つまり何が言いたいかというと、制約はあるものの自分好みな**オリジナルな乗換案内が作れちゃうんだZE☆**ということです。

#仕様書について
仕様書が申請者以外にもオープンになりました。
また、専属の担当者が今申請内容をチェックするようになりましたので以前より審査スピードが上がっているようです。
[乗換案内オープンAPI仕様書](https://biz.jorudan.co.jp/file/norikae_openAPI.pdf)

#公開時の注意事項
公開時の注意時点としては、下記の2点が必須事項です。

- オープンに利用する用途のみ許諾がおります。
    - NGな例：研究用途や個人で利用してストア公開しないアプリケーション、社内のみで使う通勤費管理システムなどなど
    - OKな例：自身で運営しているWEBページに乗換機能を追加する、ストア公開するアプリケーションに経路検索機能を載せる
- APIから返却されるジョルダン乗換案内へのリンクを必ず設置
    - 経路検索結果を表示する画面で、利用者がジョルダン乗換案内の経路ページに遷移できるリンク等をセットする必要があります。 

また利用申請の際に、どんなサービスに使われるか既存のWEBサービスへの追加の場合は、既存サービスのURL等、今後の開設サイトやアプリの場合には開設予定のURLと企画書が必要です。
~~会社で、前に座っている担当の方が人力確認しているので、レスポンス遅い場合があります。ご容赦ください。~~

複数の経路のうち、1つしか帰って来なかったり、いろいろな事情もあり列車の時刻などはAPIから返却されませんが、無料で経路検索APIが使えるのは、個人の開発者から見ても面白いと思いますので、今回はiOSエンジニアの私が個人として使ってみようと思います。

#アプリから利用するには
##クライアントからの直接接続は非対応
　そうなんです。クライアントから直接リクエスト出来るようにはなっていません。審査が許諾されたあと固定の接続元IPをジョルダン側に伝える必要があります。基本的には、不動産サイトやイベンターさんのサイトに経路検索機能をお手軽に追加するようなサービスなのでスマートフォンのアプリから直接リクエストすることはできません。
　ただ、オープンに利用する分には問題ありませんので、アプリであっても大丈夫です。(もちろん、企画の内容にもよります。)

##VPS + nginx リバースプロキシで、クライアントからのリクエストに対応する
　今回は、さくらのVPSを利用しています。今回は、ざっくりなのでnginxのインストール等々は省きます。さくらのVPS以外でも、固定IPがもらえるサービス上であれば基本問題ありません。
　nginxのサービスを立ち上げ後、下記コマンドで、nginx.confを開き、一部追記します。

```
sudo vim /etc/nginx/nginx.conf
```

```nginx
    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }

>>>     location /bizapi/ {
>>>             proxy_pass http://******/bizapi/;
>>>     }

        error_page 404 /404.html;
            location = /40x.html {
        }
   }
```
　書き換え後、nginx.confを読み直すため下記コマンドを実行します。

```
sudo nginx -s reload
```

　リクエスト回数の上限制限がありますので、本来であればキャッシュなど考える必要がありますが、今回はアプリからのリクエストなので、何もしません。また、SSL対応なども別途サービス稼働時に必要ですので、そこは各自で対応をお願いします。
　これで、クライアントからリクエストすることが可能になりましたので、下記のURIにアクセスしてみましょう。文字コードはUTF-8で返却されます。

#アプリから使ってみる
経路検索結果を見て、アプリから扱いづらい、大変そうと思ったそこの貴方。~~僕もめんどくさいと思いました。~~
iOSだけですが、簡単に検索できて、オブジェクトで返却してくれるFrameworkをご用意いたしました。

**NorikaeOpenAPIFramework**
[Gitはこちらから](https://github.com/MasamiYamate/NorikaeOpenAPIFramework)

GitのRepositoryには、Sampleプロジェクトも用意していますので、参考にしていただけると幸いです。
Sampleを実行すると下記のような経路検索結果の表示ができます。

<img width="375" alt="IMG_0214.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/114168/5988cf7d-9568-98eb-2bbc-fb830066f8e6.png">

ざっくりとしたメソッドの使い方は下記のような感じです。

```Search.swift
/// 任意の文字列から駅名検索を行います
///
/// - Parameters:
///   - keyword: 検索したい駅名のキーワード
///   - mode: 検索モードの指定 0...前方一致(デフォルト) 1...完全一致優先
/// - Returns: NOAStationの配列が返却されます。エラー発生時は、nilが返却されます。
let stations: [NOAStation]? = NorikaeOpenAPIFramework.share.searchStations ("keyword String" , mode: 0)

/// 任意の文字列から路線名検索を行います
///
/// - Parameters:
///   - keyword: 検索したい駅名のキーワード
///   - mode: 検索モードの指定 0...前方一致(デフォルト) 1...完全一致優先
/// - Returns: NOALineの配列が返却されます。エラー発生時は、nilが返却されます。
let lines: [NOALine]? = NorikaeOpenAPIFramework.share.searchLineNames ("keyword String" , mode: 0)

/// 特定の駅を通る路線名を取得します
///
/// - Parameters:
///   - keyword: 駅名検索で取得した任意の駅名
///   - mode: 検索モードの指定 0...前方一致(デフォルト) 1...完全一致優先
/// - Returns: NOALineの配列が返却されます。エラー発生時は、nilが返却されます。
let groupLines: [NOALine]? = NorikaeOpenAPIFramework.share.searchTheNameOfTheLineConnectingToTheStation ("keyword String", mode: 0)

/// 特定の路線に所属する駅名を取得します
///
/// - Parameter keyword: 路線名検索で取得した任意の路線名
/// - Returns: NOAStationの配列が返却されます。エラー発生時は、nilが返却されます。
let groupStations: [NOAStation]? = NorikaeOpenAPIFramework.share.searchForTheStationOnTheLine ("keyword String")

/// 任意の区間の経路検索を行う
///
/// - Parameters:
///   - eki1: 出発地の名称 (検索結果から得られた正式名称)
///   - eki2: 目的地の名称 (検索結果から得られた正式名称)
///   - kbn1: 出発地の区分 (NOAStationオブジェクトのtype.rawValueで取得可能)
///   - kbn2: 目的地の区分 (NOAStationオブジェクトのtype.rawValueで取得可能)
///   - date: 検索する日付 ※Optional
/// - Returns: NOARouteが返却されます。エラー発生時は、nilが返却されます。
let route: NOARoute? = NorikaeOpenAPIFramework.share.routeSearch(eki1: "DepartureName" , eki2: "ArrivalName" , kbn1: "DepartureType String" , kbn2: "ArrivalType String" , date: Date() )
```

#最後に
会社辞めました。
一応これに関しては、趣味で作ったFrameworkなのでちゃんと近いうちに作り直す予定です。