Morning Girl

Web API, Windows, C#, .NET, Dynamics 365/CRM etc..

なぜポストREST APIが求められるのか? REST APIがカバーできない2つの要因とその対策

なんだか珍しく、あおり気味のタイトルにしてしまいました。

最近読んだ以下の記事が大変おもしろかったので、今まで私の中で度々反芻していたものを文章としてまとめてみました。

gihyo.jp

なぜ今GraphQLが騒がれているのか。ポストRESTが求められている理由、なぜポストRESTが求められなければいけないのか? ポストRESTの登場によって私たちにとって何が嬉しくなるのか? そのあたりを色々と触れていきたいと思います。

本文に入る前に

  1. ここでは、RESTと記載していものに、REST ful であることも含めています。RESTの推奨(規約ではない)に準拠して開発されたAPIをREST Fulと呼ぶのであって、そこにAPIとしての違いは無いためです。

  2. どちらかと言えば、私の意識としてはパブリックなAPI、オープンデータ用のAPIであったり、KintoneやSANSAN、Salesforce、Dynamicsなどが提供しているサービス受給者側が利用するAPIを大きくイメージしています.。Client/Serverでやり取りするAPIも本質的な違いは無いかもですが、ちょっと文脈が変わると思っています。

そもそもRESTとは何か?

まず誤解を招かないように、言っておきたいのですが、RESTをディスっているわけではありません。

RESTの思想は素晴らしく、否定する気は毛頭ありません。その思想に準拠することは、Web APIをHTTPというプロトコルベースの上で適切に構築するのに役立ちます。

ただ、RESTという言葉遣いを考える上で、RESTはあまりにもプロトコルライクに語られる文脈が多いように感じます。

Wikipediaにも書かれていますが、RESTはプロトコルではありません。

以下の思想に準ずる、「ソフトウェアアーキテクチャの スタイル」のひとつ です。

Stateless:ステートレスなクライアント/サーバプロトコル

Uniform Interface:すべての情報(リソース)に適用できるHTTPメソッドの定義

Addressability:リソースを一意に識別する「汎用的な構文(URL)」の定義

Connectability:アプリケーションの情報と状態遷移の両方を扱うことができる「ハイパーメディア(リソースリンク)の使用」

上記前提の上で、役不足となる2つの理由を見ていきたいと思います。

1.実装ルールが統一されていない(規約・プロトコルではない)

例えば、RESTがだめな理由として、SQLでいうところのselectができず、Responseのオーバーヘッドが発生しやすい、という論点を幾つか見たことがあります。

ですがそれはRESTが悪いというより「RESTで決められていないことをどのように実装するのかは自由である」ことが悪いのです。

先に述べたように、RESTは準拠するべき設計思想であり、規約・プロトコルではありません。(なのでRESTの思想に則ったWeb APIをREST Fulと呼ぶ言葉まで生まれてしまうのかなぁと思います)

RESTはその原則に則ってさえいれば、結構自由に記述することができます。

HTTPのパラメータに$selectを追加しようが、POSTのBodyにJsonでパラメータを入れさせるようにしようが、実装できるのです。(※この自由さと規約のゆるさにより、RESTはある種のデファクトスタンダードとなり得ましたが、このゆるさ故に「RESTっぽい何か」が大量に作られたのもまた事実でしょう。)

では、プロトコルとして統一されているもの(RFCOASIS等で提示されたもの等)では何が存在するのか? 

少し私なりに既存するWeb APレイヤーを下記のようにまとめてみました。

f:id:sugimomoto:20180106164817p:plain

・OData

http://www.odata.org/

・GraphQL

http://graphql.org/

SOAP

https://ja.wikipedia.org/wiki/SOAP_(%E3%83%97%E3%83%AD%E3%83%88%E3%82%B3%E3%83%AB)

・gRPC

https://grpc.io/

・OpenAPI(旧名:Swagger)

https://www.openapis.org/

この中で、例えばMicorosftが主体となり標準化を進めRFCともなっているOData(Dynamics やSharePoint, Office365等がこのプロトコルに準拠しています。)に関して言えば、

データの取得アプローチがある種RDBSQLのように、RESTの思想に沿った上で、明示的に決められています。(Web siteにもOData - the best way to RESTと書かれていますね)

f:id:sugimomoto:20180106165902p:plain

http://www.odata.org/getting-started/basic-tutorial/

GraphQLはクエリそのものが、明示的にデータ取得カラムなどを規定しています。

f:id:sugimomoto:20180106170010p:plain

http://graphql.org/learn/

こういった点から、RESTが持つ欠点と、ポストRESTに求められている点が見えてくるかと思います。

2.メタデータスキーマ情報が提供されていない

REST APIには、そのREST APIがどのような仕様なのか、振る舞いをするのかを定義する要素は含まれていません。

どのURLパスに対して、どんなパラメータが有効で、どんなレスポンスが返ってくるのか、どのようなデータ形式が定義されているのか。

世の中のほとんどのREST APIは、人間用に文書化されたドキュメントを通じて、振る舞いを伝えています。

それによってどんな弊害が生まれるかといえば以下の2点が主にあげられると思います。

  1. ドキュメントと実装の乖離が発生しやすい

  2. 他のプログラムがその振る舞いを読み取り、想定することができない

ちなみに、今ではほとんど聞かなくなってしまったと感じるSOAPではWSDL(Web Services Description Language)という仕様で外部からそのRPCの関数がどんな引数を求めていて、どんな返り値をするのかを確認することができます。

<?xml version="1.0" encoding="shift_jis"?>
<wsdl:definitions
targetNamespace="http://unitec-denki.utj.co.jp/schema/2003/"
xmlns:impl="http://unitec-denki.utj.co.jp/schema/2003/"
xmlns:intf="http://unitec-denki.utj.co.jp/schema/2003/"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
         
<wsdl:message name="getPriceRequest">
<wsdl:part name="Code" type="xsd:string"/>
  <wsdl:part name="Value" type="xsd:int"/>
</wsdl:message>
         
<wsdl:message name="getPriceResponse">
  <wsdl:part name="getPriceReturn" type="xsd:int"/>
</wsdl:message>
         
<wsdl:portType name="Estimate">
  <wsdl:operation name="getPrice" parameterOrder="Code Value">
    <wsdl:input name="getPriceRequest" message="impl:getPriceRequest"/>
    <wsdl:output name="getPriceResponse"
message="impl:getPriceResponse"/>
  </wsdl:operation>
</wsdl:portType>
         
<wsdl:binding name="EstimateSoapBinding" type="impl:Estimate">
  <wsdlsoap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
  <wsdl:operation name="getPrice">
    <wsdlsoap:operation soapAction=""/>
    <wsdl:input name="getPriceRequest">
      <wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://unitec-denki.utj.co.jp/schema/2003/"/>
    </wsdl:input>
    <wsdl:output name="getPriceResponse">
      <wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://unitec-denki.utj.co.jp/schema/2003/"/>
    </wsdl:output>
  </wsdl:operation>
</wsdl:binding>
         
<wsdl:service name="EstimateService">
  <wsdl:port name="Estimate" binding="impl:EstimateSoapBinding">
    <wsdlsoap:address
location="http://localhost:8080/axis/services/Estimate"/>
  </wsdl:port>
</wsdl:service>
         
</wsdl:definitions>

www.atmarkit.co.jp

ODataではXML形式で、クエリすることができるデータソースのフィールドやKeyのスキーマ情報を確認することが可能です。

f:id:sugimomoto:20180106172039p:plain

ちなみに、このREST不足を補うために、OpenAPI(旧名:Swagger)は登場しました。

YAMLを使って、外部からそのWeb APIを規定するための仕様です。これを使うことで、ドキュメントからWeb APIのプログラムのベースを生成したり、人間用のドキュメントも生成することができます。

では上記要素に則ってWebAPIを作った場合、何が嬉しいのか?

開発がし易い、とは安易に言いません。もちろん、振る舞いが公開されるので、Web APIのテストが実施しやすくなりますし、ドキュメントとの乖離も発生しづらくなるでしょう。

あえて一つ明言するとすれば、スケールがし易いと私は表現するべきかなと思います。

RESTはその柔軟さ故に、例えば様々なサードパーティツールがそのWeb APIを使う際の敷居を高くしてしまいます。

例えば、Web APIを最も今求めているであろう、BIツール製品。BIツールが繋がるWeb APIは、そのBIツールそのものが内部組み込みとして提供しているタイプ、プロコルとして世に出ているものへ接続するタイプの2種類が主に存在します。

Microsoft製のBIツールであるPower BIであれば、以下のようにMicrosoft系製品を主体としたWeb API・サービス郡(DynamicsやAzure等)が標準組み込みとして提供されています。

f:id:sugimomoto:20180106170034p:plain

しかしながら、今世の中には2万近くにのぼるWeb APIが存在するらしいので、それにマイクロソフト自身で一つ一つ対応するのは、あまりにもコストパフォーマンスが悪すぎます。

そこで、前述したODataの接続窓口を儲けており、これによってODataで作られたWeb APIであれば、PowerBIで扱えるように構成されています。

f:id:sugimomoto:20180106170040p:plain

このように、規約に準じることは、開発者がただ使いやすくなるだけではなく、他のアプリケーションやフレームワークとの親和性を高め、Web APIをもっと使ってもらい、もっとスケールする上で要ともなります。

わかりやすい例としてBIツールをあげましたが、ここに見られるように昨今Web APIを使うのは、技術者だけではなくなってきています。IFTTTや上記BIツールのように、暗黙的にエンドユーザーが利用する機会がどんどん増えています。開発者向けツールであればなおさらだと思います。

では、既存の大多数のRESTっぽいAPIはどうするべきか?

最後に、より使ってもらいやすい、使いやすいWeb APIにするに、既存のREST APIはどのような手段を取るべきか、私の見解ですが記しておきたいと思います。

  1. 標準化されたプロトコルに準拠して開発し直す(ないし新しく開発するものを準拠する)

    理屈で言えばこれが一番真っ当なのでしょうが、一番難易度が高いものでもあります。

    でも、はっきりしているのは、ドキュメント仕様、スキーマ情報が公開されていない状態ではいけない、ということでしょう。

  2. OpenAPIを利用する

    上記で前述したようにOpenAPIは外部から既に構築されているREST APIを定義することができます。

    最近はMicrosoftのサーバーレスワークフローであるFlowからも接続することができるようになり、RESTちっくなWeb APIを様々なアプリケーションと互換性を持たせるためのハブとしても、期待されているものでもあります。

    まだ対応するツールが多いとは言えませんが、一から開発し直すよりも取り組む敷居がある程度低く、ドキュメントの自動生成等の恩恵もそれなりにあるので、今RESTちっくなAPIを公開しているだけであれば、是非試すべき手段かなと思います。

  3. パートナーと組む

    私の中で、私の勤めている会社が、この文章を記す上での文脈である以上、これに触れないわけにはいきません。

    www.cdata.com

    CData Softwareでは、SalesfoceやMarketo、Kintoneなどの様々なWeb APIRDBデファクトスタンダードなテクノロジーであるJDBCODBCADO.NETといったドライバーを経由してSQLでクエリすることができるライブラリを販売しています。

    ODataにそっていれば、様々なWeb APIを同じようにクエリすることができるように、CDataのドライバーを利用することで様々なアプリケーションから、RESTちっくなWeb APIも、SOAPも、SQLを通じてクエリすることができるようになります。 既存のWeb APIプロトコル化してしまう、仮想RDBにしてしまう、と言ってもいいかと思います。

    このドライバーを既存のAPIに被せることによって、様々なツール(BI・ETL・プログラミング言語)とWeb APIを繋ぐためのHubとして利用することができますので、一つの手段として是非見てもらえたらなと思います。

おわりに

個人的にGraphQLなどを語る上で、RESTと比較するのはあまりよろしくないと感じています。(いい比較対象が無いのも事実なんですが、せめてODataと比較してほしいと思ったりです)

何をプロトコルと呼ぶのかについては、いろいろな議論があるでしょうが、RESTは他のプロトコル郡と比較するには、自由であるゆえに、比較対象としてはあまりにも脆弱です。

それを踏まえた上で、もっといろんな比較が増えてくると嬉しいなぁと思います。

さて、私個人としては、将来的に何がデファクトスタンダード、ポストRESTになるかと言うよりは、関数ライクなRPCと表形式データクエリ専門が共存していくのではないかなと思っています。

そのため、GraphQLとgRPCが話題にあがっているのだろうと。ただ、それでも実装負荷を考えると、REST+OpenAPIのパターンは、難しい点は色々とあれど開発者にとっても優しい実装パターンとして、まだまだ広まる余地が多いよなぁとも感じたり。

いずれ、またこの話題には、1年後ぐらいに触れてみたいところですね。

以上です。

PS.色々とご意見もらえると大変ありがたいです。