CData Software Blog

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

コードも書けない人がはじめてドライバーを作る笑いと涙の物語~REST Driver 定義の作り方~

こんばんは。CData Japan の疋田です。

CData の日本ビジネスを立ち上げて6年が経ちました。この製品が好きになってからだと8年ぐらいです。ずっとやりたかったことが「自分でデータドライバーを作る」ということです。今回、CData Software Advent Calendar 2021 を機に、念願のドライバー開発をやってみました!

ちなみに私、ビジネスサイドの担当でして、いわゆるセールスの人です。非エンジニアです。データは見たり使ったりしますが、コード書けません。でも、とりあえずCData Driver を作ってみたい!思いは誰にも止められません。

いざっ!

Twitter で実況中継していた内容はこちらにまとめました(はづかしい):

togetter.com

CData Driver とは?

CData では、DB だけでなく各種SaaS API などをSQL でクエリするデータドライバー・コネクタを提供しています。データ操作ではSQL の地位は圧倒的です。ほぼすべてのBI ツール、データ分析ツール、データ連携ツールは中ではSQL で動いています。40年以上の歴史に裏付けられ、かっちりと規格化され、利用するエンジニアも圧倒的に多いです。そのSQLSaaS を含めあらゆる業務データを扱えるようにしようというのがCData のミッションです。

www.cdata.com

ドライバー化するAPI を決める

データとなるAPI ですが、選んだ基準は以下でした:

  • REST API

  • シンプルなもの

  • データとして見て触ってたのしいもの

業務アプリ系はREST API といってもJSON 構造が複雑なものが多く(本当に多い)、ハードルが高そうだったので、好きなアメフトのNFL のデータをAPI で提供しているsportsdata のAPI を選びました。

sportsdata.io

まずはAPI と仲良くなる - Postman で普通にAPI を呼ぶ

API のようなものは、他のソフトウェアと同じで、「とりあえず触ってみる」ことが大事です。ソフトウェアもインストールしてまず動かすまで(TTFHW、Time to Firt Hellow World)までが大変に思えるだけです。とにかくまずは触ってみることでハードルを下げることができます。

API をコーディングなしで呼び出すために Postman というツールを使いました。

www.postman.com

まずは使うエンドポイントを決めます。News https://api.sportsdata.io/v3/nfl/scores/json/News というエンドポイントを使います。

ID などの値を渡さなくてもデータを取ってくれそうなのが初心者には大事です。

認証は、API Key を使ったシンプルなトークン認証でした。

This is the documentation for SportsDataIO's NFL API. All of our API endpoints can be accessed via an HTTP GET request using your API key. The API key can be passed either as a query parameter or using the following HTTP request header. Ocp-Apim-Subscription-Key: {key}

GET メソッドを選択、URL を入れて、ヘッダーにAPI Key を入れます。

プロパティ
メソッド GET
URL https://api.sportsdata.io/v3/nfl/scores/json/News
ヘッダー名 Ocp-Apim-Subscription-Key
ヘッダー値 API Key

f:id:cdatasoftware:20211207000328p:plain

Send を押して無事にAPI を呼び出すことができました。 f:id:cdatasoftware:20211207001354p:plain

スキーマ定義ファイル .rsd ファイルの作成

ここからREST Driver が参照するスキーマ定義ファイルを作っていきます。.rsd という拡張子でスキーマは定義され、.rsd ファイルは.XML 形式で記述されます。1 テーブル1 .rsd ファイルです。

詳しい説明はこちら:

www.cdata.com

カラム定義

以下の形式でx:path にデータソースのカラム、attr にテーブルにマッピングした際のテーブル名を定義していきます。データ型を付与することで、その後のBI やデータ連携ツールでのデータの可用性を圧倒的に高められます。

<api:script xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:api="http://apiscript.com/ns?v1" >
<!--Sets the table name and description and contains the column definitions-->

    <api:info xmlns:other="http://apiscript.com/ns?v1" title="News" desc="Get all the News">
    <!--Individual column definitions-->
        <attr name="NewsID" key="true" xs:type="string" readonly="true" other:xPath="NewsID" />
        <attr name="Source"           xs:type="string" readonly="true" other:xPath="Source" />
        <attr name="Updated"            xs:type="datetime" readonly="true" other:xPath="Updated" />
        <attr name="TimeAgo"          xs:type="string" readonly="true" other:xPath="TimeAgo" />
        <attr name="Title"              xs:type="string" readonly="true" other:xPath="Title" />
        <attr name="Content"             xs:type="string"    readonly="true" other:xPath="Content" />
        <attr name="Url"              xs:type="string" readonly="true" other:xPath="Url" />
        <attr name="TermsOfUse"     xs:type="string" readonly="true" other:xPath="TermsOfUse" />
        <attr name="Author"            xs:type="string" readonly="true" other:xPath="Author" />
        <attr name="Categories"            xs:type="string" readonly="true" other:xPath="Categories" />
        <attr name="PlayerID"             xs:type="string" readonly="true" other:xPath="PlayerID" />
        <attr name="TeamID"                xs:type="string" readonly="true" other:xPath="TeamID" />
        <attr name="Team"               xs:type="string" readonly="true" other:xPath="Team"/>
        <attr name="PlayerID2"           xs:type="string" readonly="true" other:xPath="PlayerID2"/>
        <attr name="TeamID2"             xs:type="string" readonly="true" other:xPath="TeamID2" />
        <attr name="Team2"               xs:type="string" readonly="true" other:xPath="Team2"/>
        <attr name="OriginalSource"       xs:type="string" readonly="true" other:xPath="OriginalSource" />
        <attr name="OriginalSourceURL"           xs:type="string" readonly="true" other:xPath="OriginalSourceUrl" />
    </api:info>

グローバルパラメータの作成

次にどんなルールでAPI に接続するかを定義していきます。

  • URL はAPI を呼び出すURL を設定

  • このAPI ではヘッダーに"Ocp-Apim-Subscription-Key" という名前でAPI Key を入れてリクエストする認証方式なので、以下のようにアトリビュートを設定します。

    <!-- Setting global parameters -->
    <api:set attr="ContentType" value="application/json" />
    <api:set attr="EnablePaging" value="true" />
    <api:set attr="RepeatElement" value="/" />
    <api:set attr="uri" value="https://api.sportsdata.io/v3/nfl/scores/json/News" />
    <api:set attr="header:name" value="Ocp-Apim-Subscription-Key"/>
    <api:set attr="header:value" value="[_connection.apikey]"/>

メソッド

どのようなメソッドを許容するかを定義します。 このAPI は呼び出しだけなので、GET だけを定義しました。

    <api:script method="GET">
        <api:set attr="method" value="GET" />
        <api:call op="jsonproviderGet">
            <api:push/>
        </api:call>
    </api:script>

このようなファイルをテーブルの数だけ作ればOK です。

失敗

最初なのでいろいろとつまずきました。

シロウトなのでXML のタグが壊れている

XML で.rsd は記述するのですが、やはりシロウトはキチンと掛けません。Visual Studio Code がちゃんと.rsd 拡張子のファイルをXML としてシンタックスハイライトしてくれないのでなおさらチェックが自分の目という心もとなさです。

エラーでタグが壊れていると言われたので、どうしようか悩んでいたら、VS Code に.rsd 拡張子をXML として使える定義がありました。ウチのエンジニアの杉本氏が使いかたを書いていてくれました。ありがとう。

kageura.hatenadiary.jp

では、*.rsd をxml で定義、と。

f:id:cdatasoftware:20211207073623p:plain

これでハイライトが効くようになったので、無事に壊れているタグを見つけられました。

f:id:cdatasoftware:20211207073900p:plain

ってかさ、最後の閉じるタグって、サンプルは上の方から読んでくと書いてないんだよね。まあ、タグは閉じるの当然なんでしょうけど。

</api:script>

認証

トークン認証でもBASIC 認証でもOAuth 2.0 でもAPI には多かれ少なかれ認証が必要です。認証部分をグローバルパラメータで記述します。CData Drivers の場合にはODBC でいえばDSN 設定画面、JDBCODBC でいえば接続文字列URL でいろいろな種類の認証を一枚のレイヤーで通せるようになっています。

今回は、以下のようにヘッダー部分に接続文字列のapikey を渡すような定義で書かれました。これは全然わからなかったので、ウチのエンジニアさんたちに教えてもらいました。この部分のサンプル集を強く求めたいところです。OAuth 2.0 など複数のやり取りが発生する認証でもここの定義でカバーしているのです。

    <api:set attr="header:name" value="Ocp-Apim-Subscription-Key"/>
    <api:set attr="header:value" value="[_connection.apikey]"/>

REST Driver とAPI Driver ではメソッドが違う

これは覚えておこうレベル。

REST Driver:

<api:script method="GET">
        <api:set attr="method" value="GET" />
        <api:call op="jsonproviderGet">

API Driver:

<api:script method="GET">
        <api:set attr="method" value="GET" />
        <api:call op="apisadoExecuteJSONGet">

実際にツールからつないでみる

今回はODBC Driver for REST という汎用のREST Driver を使ってこのsportsdata APISQL でつないでみます。

ODBC のDSN を作成

まずはCData ODBC Driver for REST をダウンロードしてインストールします。

www.cdata.com

ODBC のDSN を開いてsportsdata につなぐ設定をします。

必要なプロパティは今回は二つだけです。Location に上で作った.rsd ファイルのフォルダを指定します。同じデータソースで複数のテーブルを定義した場合には複数の.rsd を入れておけば、一つのスキーマ定義の中の複数のテーブルという形で使えます。

次にOther プロパティでAPIkey を入力します。先ほどのグローバルプロパティでヘッダーに渡したい認証情報をapikey= で渡せるように定義したものです。

|プロパティ|値| |---|---| | Location | C:\demo\NFL など先ほどの.rsd を格納したフォルダ名 | | Other | apikey=xxxxx | f:id:cdatasoftware:20211207074826p:plain

Visual Studio のサーバーエクスプローラーからSQL で接続

ここまでくるとただのODBC DSN ですのであとはBI でもExcel でもAccess でも開発環境からでもなにからでもアクセスが可能です。とりあえずVisual Studio のサーバーエクスプローラーでクエリだけしてみました。

SELECT * FROM news

ちゃんとSQL で呼び出せました!!! 

f:id:cdatasoftware:20211207075241p:plain

非エンジニアだけどドライバーを作ってみて

製品の解像度が上がる→セールスで説得力UP!

単純なAPI への接続ですが、自分で定義を作ってみることでCData がどうやってAPI をパースしてSQL で使えるようにしているのかの解像度が上がります。セールスや社内の開発チームとの話でももっと理解できる部分が増えたと思います。解像度が上がれば、ディスカッションできる部分が増えるので説得力が増します。

エンジニアさんからの生暖かい共感→エンジニアさんとの距離が縮まる

エンジニアと非エンジニアって、越えられない壁があると思います。よい意味でエンジニアさんたちがやっていることは偉いです。PC の前で新しい世界を作っているんですから。

でも非エンジニアであるビジネス系、セールス系の人は壁を甘んじていてよいかというとそうではないです。最低限、自分の会社の製品は触りましょう。これをやらないセールスやビジネスの方は失格です。「今回のAPI ドライバーを作る」は製品を触るという中では難易度が高かったですが、とにかくやることが大事。エンジニアさんたちはこういう初歩的な挑戦を温かく見守ってくれました。

そうすることでやっぱり、自分とエンジニアさんの距離、そして自分と製品との距離がぐっと縮まります。非エンジニアの壁の向こうからこんにちわ。これは好きな異性とかいたら、相手の趣味とかを自分でも試そうとか思いますよね?それと同じです。「ちょっと面倒なヤツで全然わかってないけど、努力はみとめてやろう。」というやつです。エンジニアさん尊敬しているので、こうやってアプローチするのは当然というやつです。

以上です。お付き合いいただき、ありがとうございました。