こんにちは。CData Software Japan リードエンジニアの杉本です。
先月不動産テック協会と株式会社Geoloniaが公開した日本全国の町丁目レベルのオープンデータ(18万件以上!)が話題になりましたね。
internet.watch.impress.co.jp
公式ページはこちらから。
geolonia.github.io
しかもそのデータがGithubでCSVとして公開されており、マスタデータとして今まで管理・運用しづらかった住所データの新しいカタチを提供してくれそうで、とても嬉しいですね。
github.com
とはいえ、CSVとして公開されていても、なかなか外部のアプリケーションから扱いやすいか? と言われると、やはり一度RDBなどにマスタデータとして落とし込むか、APIを挟むといったアプローチをしなければ、実活用までにはワンステップ足りない、というのが実情ではないでしょうか。
そこで今回はこのCSVデータを他のアプリケーションから使いやすいように CData API Server で API化する方法を紹介したいと思います。
完成イメージ
元データは以下のようなCSVですが
以下のようにJSONを返すAPIとしてアクセスできるようにします。
併せて以下のようなAPIドキュメントも生成されます。
なお、元データはRDBなどには入れず、APIがリクエストされたタイミングでGithub上のCSVデータを取得して、レスポンスを返す仕組みになっています。
なので、元データが同じURIで最新化される限り、常に最新のデータにアクセスが可能です。
手順
それでは構築手順を説明していきます。
必要なもの
API Server 環境構築
今回 API Server は AWS EC2:Amazon Linux に構築しました。
以下のページからCross-Platform(Java Edition)をダウンロードして、ZIPファイルに含まれる「setup.jar」を実行し、インストールを行います。
https://www.cdata.com/jp/apiserver/download/
http://cdn.cdata.com/help/BWF/jp/odata/Starting-Server.html
また、併せてJDBC Driverも対象のマシンにインストールします。
https://www.cdata.com/jp/drivers/csv/jdbc/
インストール後、JDBCの本体をapiserverのlibフォルダに移動させておきます。
$ mv /home/ec2-user/cdata.jdbc.csv.* /opt/apiserver/lib/
インストール方法の詳しい手順はクラスメソッド小林さんのブログ記事でも紹介されていますので、こちらも参照してみてください。
https://dev.classmethod.jp/articles/cdada-api-server-al2/
CSVデータソースへの接続
インストール完了後、API Server の管理画面にアクセスして、「設定」→「接続」から「CSV」の接続を追加します。
接続プロパティでは、以下のように設定を行います。すべてAdvancedのタブに入っているので注意しましょう。
接続文字列で以下のように指定しても大丈夫です。
jdbc:cdata:csv:URI=https://raw.githubusercontent.com/geolonia/japanese-addresses/master/data/latest.csv;IncludeColumnHeaders=False;SkipTop=1;
ポイントは「Include Column Headers」と「SkipTop」のプロパティです。
APIとして定義し直す際に、日本語のオブジェクト名から変更するので、この1行目をスキップするように構成しています。
APIリソースの定義
接続設定を追加したら、APIのリソース定義を作成します。
「リソース」から「リソースを追加」をクリックし
先程作成した接続設定を選択します。
次の対象となるCSVデータ(ここでは一つだけ)を選択します。
最後にAPIのリソース名やカラム名を定義します。
現在カラム名は前の手順で日本語のヘッダーを無視したので、列番号がそのまま付与されている状態です。これを英語名に置き換えていきます。
また、許可するメソッドもデータの取得のみが対象となるので、GETだけにしましょう。
最終的に以下のような定義になります。
CData API Serverのリソース定義はXMLで保持されています。以下のXMLを貼り付ければそのまま利用できますので、使ってみてください。
<apiscript xmlnsapi="http://www.rssbus.com/ns/rsbscript/2">
<apiinfo title="[CData].[CSV].[latest.csv]" connection="Conn1" restrictUser="" description="作成、更新、クエリ、および削除 CData.CSV.latest.csv">
name="Col0" alias="PrefectureCode" key="false" type="int" isNullable="true" readonly="false" desc="都道府県コード" />
name="Col1" alias="PrefectureName" key="false" type="string" columnsize="2000" isNullable="true" readonly="false" desc="都道府県名" />
name="Col10" alias="Longitude" key="false" type="double" isNullable="true" readonly="false" desc="緯度" />
name="Col11" alias="Latitude" key="false" type="double" isNullable="true" readonly="false" desc="経度" />
name="Col2" alias="PrefectureNameKana" key="false" type="string" columnsize="2000" isNullable="true" readonly="false" desc="都道府県名カナ" />
name="Col3" alias="PrefectureRoma" key="false" type="string" columnsize="2000" isNullable="true" readonly="false" desc="都道府県名ローマ字" />
name="Col4" alias="CityCode" key="false" type="int" isNullable="true" readonly="false" desc="市区町村コード" />
name="Col5" alias="CityName" key="false" type="string" columnsize="2000" isNullable="true" readonly="false" desc="市区町村名" />
name="Col6" alias="CityNameKana" key="false" type="string" columnsize="2000" isNullable="true" readonly="false" desc="市区町村名カナ" />
name="Col7" alias="CityNameRoma" key="false" type="string" columnsize="2000" isNullable="true" readonly="false" desc="市区町村名ローマ字" />
name="Col8" alias="SectionCode" key="false" type="long" isNullable="true" readonly="false" desc="大字町丁目コード" />
name="Col9" alias="SectionName" key="false" type="string" columnsize="2000" isNullable="true" readonly="false" desc="大字町丁目名" />
apiinfo>
<apiscript method="GET">
<apipush op="apiSelect" />
apiscript>
apiscript>
APIアクセスユーザーの追加
リソースの作成が完了したら、APIにアクセスするユーザーも登録しておきましょう。登録後、認証用のトークンが生成されるので、後ほど使用します。
ページネーションの設定
最後にページネーションの設定を行います。CData API Server はクエリパラメータを指定しない限り、デフォルトで全レコードをレスポンスしてしまいます。
現在対象のCSVには18万件データが存在するので、そのままでは使いづらいですね。なので、「サーバー」の設定から「サーバーサイドページングサイズ」に1リクエストで取得されるデフォルトのレコード数を指定することで、これを回避します。
今回は100件と指定してみました。
APIにアクセスしてみる
それでは作成したAPIにアクセスしてみましょう。
APIタブから「/api.rsc/japanese_addresses」に移動すると、作成したAPIのリファレンスが確認できます。
エンドポイントURLにそのままアクセスしてみると、以下のようにもともとCSVだったデータがアプリケーションから扱いやすいJSON形式になって取得できました。
Postmanから色んなクエリを使ってアクセスしてみる
次にPostmanからもアクセスしてみます。認証には、User登録時に生成されたTokenを使用します。ヘッダー「x-cdata-authtoken」で生成されたTokenを指定しましょう。
GET /api.rsc/japanese_addresses/ HTTP/1.1
Host: ec2-3-112-205-162.ap-northeast-1.compute.amazonaws.com:8080
x-cdata-authtoken: 4r7Z5x2e0V6b3f7Q1z0u
CData API Server では多様なクエリをサポートしているので、柔軟なフィルター・検索を行うことが可能です。
詳しくはこちらのヘルプも参考にしてみてください。
例えば完全一致検索の場合は「$filter=PrefectureCode eq 2」のような形式でクエリできます。また、上位N件の取得も「$top=3」というパラメータで指定できます。
GET /api.rsc/japanese_addresses/?$filter=PrefectureCode eq 2&$top=3 HTTP/1.1
Host: ec2-3-112-205-162.ap-northeast-1.compute.amazonaws.com:8080
x-cdata-authtoken: 4r7Z5x2e0V6b3f7Q1z0u
$filterはAND条件で絞り込んでいくことも可能です。これで、県、市区で絞り込んでいくことも可能ですね。
GET /api.rsc/japanese_addresses/?$filter=PrefectureName eq '宮城県' and CityName eq '仙台市太白区'&$top=3 HTTP/1.1
Host: ec2-3-112-205-162.ap-northeast-1.compute.amazonaws.com:8080
x-cdata-authtoken: 4r7Z5x2e0V6b3f7Q1z0u
「$filter=contains(SectionName,'八木山')」という形式で部分一致検索もできます。番地を調べる時にはこういったクエリもいいですね。
GET /api.rsc/japanese_addresses/?$filter=contains(SectionName,'八木山')&$top=3&$select=PrefectureName,CityName,SectionName HTTP/1.1
Host: ec2-3-112-205-162.ap-northeast-1.compute.amazonaws.com:8080
x-cdata-authtoken: 4r7Z5x2e0V6b3f7Q1z0u
おわりに
このようにCData API Server はRDB以外にもCSVなどのデータをAPI化するのにも活用できます。
さらに今回はローカルにあるCSVではなくHTTPアクセスが可能なCSVファイルを指定することで、パブリックなデータをアプリケーションが使いやすいインタ―フェースとして定義するというアプローチにも利用できることを紹介してみました。
オープンデータが増えるに連れ、プログラムサイドからより良く使えるようにしたい、という要求は増えていくと思います。
是非こういったアプローチもAPI連携の一つの手段として試してみてもらえればなと思います。
関連コンテンツ