CData Software Blog

クラウド連携のCData Software の技術ブログです。

全国の住所のオープンデータ「Geolonia 住所データ」をCData API Server で API化してみる

f:id:sugimomoto:20200921123139p:plain

こんにちは。CData Software Japan リードエンジニアの杉本です。

先月不動産テック協会と株式会社Geoloniaが公開した日本全国の町丁目レベルのオープンデータ(18万件以上!)が話題になりましたね。

internet.watch.impress.co.jp

公式ページはこちらから。

geolonia.github.io

しかもそのデータがGithubCSVとして公開されており、マスタデータとして今まで管理・運用しづらかった住所データの新しいカタチを提供してくれそうで、とても嬉しいですね。

github.com

とはいえ、CSVとして公開されていても、なかなか外部のアプリケーションから扱いやすいか? と言われると、やはり一度RDBなどにマスタデータとして落とし込むか、APIを挟むといったアプローチをしなければ、実活用までにはワンステップ足りない、というのが実情ではないでしょうか。

そこで今回はこのCSVデータを他のアプリケーションから使いやすいように CData API Server で API化する方法を紹介したいと思います。

完成イメージ

元データは以下のようなCSVですが

f:id:sugimomoto:20200921122330p:plain

以下のようにJSONを返すAPIとしてアクセスできるようにします。

f:id:sugimomoto:20200921122341p:plain

併せて以下のようなAPIドキュメントも生成されます。

f:id:sugimomoto:20200921122349p:plain

なお、元データは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/

f:id:sugimomoto:20200921122357p:plain

http://cdn.cdata.com/help/BWF/jp/odata/Starting-Server.html

また、併せてJDBC Driverも対象のマシンにインストールします。

https://www.cdata.com/jp/drivers/csv/jdbc/

f:id:sugimomoto:20200921122403p:plain

インストール後、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」の接続を追加します。

f:id:sugimomoto:20200921122417p:plain

接続プロパティでは、以下のように設定を行います。すべてAdvancedのタブに入っているので注意しましょう。

プロパティ名 説明
URI CSVのエンドポイントURI https://raw.githubusercontent.com/geolonia/japanese-addresses/master/data/latest.csv
Include Column Headers ヘッダーカラムを含めるかどうか False
SkipTop 何行目から読み取るか 1

接続文字列で以下のように指定しても大丈夫です。

jdbc:cdata:csv:URI=https://raw.githubusercontent.com/geolonia/japanese-addresses/master/data/latest.csv;IncludeColumnHeaders=False;SkipTop=1;

f:id:sugimomoto:20200921122423p:plain

ポイントは「Include Column Headers」と「SkipTop」のプロパティです。

APIとして定義し直す際に、日本語のオブジェクト名から変更するので、この1行目をスキップするように構成しています。

f:id:sugimomoto:20200921122433p:plain

APIリソースの定義

接続設定を追加したら、APIのリソース定義を作成します。

「リソース」から「リソースを追加」をクリックし

f:id:sugimomoto:20200921122439p:plain

先程作成した接続設定を選択します。

f:id:sugimomoto:20200921122445p:plain

次の対象となるCSVデータ(ここでは一つだけ)を選択します。

f:id:sugimomoto:20200921122451p:plain

最後にAPIのリソース名やカラム名を定義します。

現在カラム名は前の手順で日本語のヘッダーを無視したので、列番号がそのまま付与されている状態です。これを英語名に置き換えていきます。

また、許可するメソッドもデータの取得のみが対象となるので、GETだけにしましょう。

f:id:sugimomoto:20200921122457p:plain

最終的に以下のような定義になります。

f:id:sugimomoto:20200921122504p:plain

CData API Serverのリソース定義はXMLで保持されています。以下のXMLを貼り付ければそのまま利用できますので、使ってみてください。

<api:script xmlns:api="http://www.rssbus.com/ns/rsbscript/2">

  <api:info title="[CData].[CSV].[latest.csv]" connection="Conn1" restrictUser="" description="作成、更新、クエリ、および削除 CData.CSV.latest.csv">
      <!-- カラム定義 -->
    <attr name="Col0" alias="PrefectureCode" key="false" type="int"   isNullable="true" readonly="false" desc="都道府県コード" />
    <attr name="Col1" alias="PrefectureName" key="false" type="string" columnsize="2000"  isNullable="true" readonly="false" desc="都道府県名" />
    <attr name="Col10" alias="Longitude" key="false" type="double"   isNullable="true" readonly="false" desc="緯度" />
    <attr name="Col11" alias="Latitude" key="false" type="double"   isNullable="true" readonly="false" desc="経度" />
    <attr name="Col2" alias="PrefectureNameKana" key="false" type="string" columnsize="2000"  isNullable="true" readonly="false" desc="都道府県名カナ" />
    <attr name="Col3" alias="PrefectureRoma" key="false" type="string" columnsize="2000"  isNullable="true" readonly="false" desc="都道府県名ローマ字" />
    <attr name="Col4" alias="CityCode" key="false" type="int"   isNullable="true" readonly="false" desc="市区町村コード" />
    <attr name="Col5" alias="CityName" key="false" type="string" columnsize="2000"  isNullable="true" readonly="false" desc="市区町村名" />
    <attr name="Col6" alias="CityNameKana" key="false" type="string" columnsize="2000"  isNullable="true" readonly="false" desc="市区町村名カナ" />
    <attr name="Col7" alias="CityNameRoma" key="false" type="string" columnsize="2000"  isNullable="true" readonly="false" desc="市区町村名ローマ字" />
    <attr name="Col8" alias="SectionCode" key="false" type="long"   isNullable="true" readonly="false" desc="大字町丁目コード" />
    <attr name="Col9" alias="SectionName" key="false" type="string" columnsize="2000"  isNullable="true" readonly="false" desc="大字町丁目名" />
  </api:info>

    <!-- オペレーション定義 -->
  <api:script method="GET">
    <api:push op="apiSelect" />
  </api:script>

</api:script>

APIアクセスユーザーの追加

リソースの作成が完了したら、APIにアクセスするユーザーも登録しておきましょう。登録後、認証用のトークンが生成されるので、後ほど使用します。

f:id:sugimomoto:20200921122514p:plain

ページネーションの設定

最後にページネーションの設定を行います。CData API Server はクエリパラメータを指定しない限り、デフォルトで全レコードをレスポンスしてしまいます。

現在対象のCSVには18万件データが存在するので、そのままでは使いづらいですね。なので、「サーバー」の設定から「サーバーサイドページングサイズ」に1リクエストで取得されるデフォルトのレコード数を指定することで、これを回避します。

今回は100件と指定してみました。

f:id:sugimomoto:20200921122520p:plain

APIにアクセスしてみる

それでは作成したAPIにアクセスしてみましょう。

APIタブから「/api.rsc/japanese_addresses」に移動すると、作成したAPIのリファレンスが確認できます。

f:id:sugimomoto:20200921122526p:plain

エンドポイントURLにそのままアクセスしてみると、以下のようにもともとCSVだったデータがアプリケーションから扱いやすいJSON形式になって取得できました。

f:id:sugimomoto:20200921122532p:plain

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

f:id:sugimomoto:20200921122542p:plain

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

f:id:sugimomoto:20200921122551p:plain

$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

f:id:sugimomoto:20200921122558p:plain

「$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

f:id:sugimomoto:20200921122607p:plain

おわりに

このようにCData API Server はRDB以外にもCSVなどのデータをAPI化するのにも活用できます。

さらに今回はローカルにあるCSVではなくHTTPアクセスが可能なCSVファイルを指定することで、パブリックなデータをアプリケーションが使いやすいインタ―フェースとして定義するというアプローチにも利用できることを紹介してみました。

オープンデータが増えるに連れ、プログラムサイドからより良く使えるようにしたい、という要求は増えていくと思います。

是非こういったアプローチもAPI連携の一つの手段として試してみてもらえればなと思います。