SalesforceのREST APIをAPIGatewayでラップする話

[Salesforce Platform Advent Calendar 2017](https://qiita.com/advent-calendar/2017/salesforce-platform) 14日目!!。フレクト4連続投稿は3日目になります。

「Salesforceのデータを別のアプリケーションから利用したい」
という要件はよくあるかなと思います。
そのために、Salesforceも様々なAPIを提供していますし、Apexを使って独自のAPIを公開することもできます。。。。が、

**正直ツラミもいっぱいありますよね!!**~~(ガバナとかガバナとかガバナとか)~~

そんな、Salesforceだけだと、若干手の届かない痒いところに、AWSのサービスを組み合わせてあげるとお互いの良いところを生かして、APIの開発/運用がやりやすくなるよ、というお話です。


# 今回紹介する構成について
下記のような構成をご紹介します。
![APIGateway_SF.png](https://qiita-image-store.s3.amazonaws.com/0/54228/4dc2f000-fb06-e072-6582-c1a78868b08a.png)

SalesforceのAPIの前にAPIGatewayを立てることで、

* クライアントから使いやすいAPIを提供する
* APIの運用を楽にする
* Salesforceの制約を緩和する

ことを目的にしています。
(LambdaはSalesforceのAPIへのルーティングとSalesforceへのログインのために利用しています。)

# 前提知識
今回はSalesforce Platformのアドベントカレンダーとして書いているので、念のため、AWSのサービスは簡単に紹介しておきます。
(知っている人は読み飛ばしてください)
## Amazon APIGatewayとは
Amazon APIGatewayはフルマネージドでRESTfulAPIが作成できるサービスです。
認証やアクセスコントロール、トラフィック管理、キャッシュ、モニタリングなど、APIの開発/運用に必要なものが一通り提供されています。
AWSの各種リソースへのGatewayになることはもちろん、httpで公開されている外部サービスにも接続可能です。

詳しくはAWSのドキュメントをご参照ください。
http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/welcome.html

## AWS Lambdaとは
AWS LambdaはFaas(Function-as-a-Service)と呼ばれる、サーバを用意せずにコードが実行できるサービスです。
APIGatewayとAWS上の各種ストレージサービスなどを組み合わせてサーバなしでWebサービスを開発する(Serverlessと呼ばれる)ような使い方も有名ですが、
今回は主にSalesforceへのログインとルーティングのために利用しています。

こちらも詳しくはAWSのドキュメントをご参照ください。
http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html

--- 

あと~~何か間違って~~AWS関係でこの記事を見た方のためにApex RESTについても紹介しておきましょう。
## Apex RESTとは
Salesforce Platform上でアプリケーションを記述するためのJavaライクな型付言語である「Apex」を利用して、
Salesforce上にRESTfulなAPIを構築できる仕組みです。

詳しくはSalesforceのドキュメントをご参照ください。
https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_rest.htm

# この構成の目的
この構成の目的をもう少し詳しく説明します

## クライアントから使いやすいAPIを提供する
### SDKの提供
Apex RESTで提供されるAPIを利用するためには、[OAuth2.0に従った認証](https://developer.salesforce.com/docs/atlas.ja-jp.api_rest.meta/api_rest/intro_understanding_authentication.htm)を実施する必要があります。
OAtuh2.0はオープンな仕様で様々な場所でも利用されているので、ハードルは高くありませんが、一手間かかってしまうのは事実ですよね。

実はAPIGatewayには特定の言語とプラットフォーム向けですがSDKを生成する機能が提供されています。
これを利用することでクライアント側は簡単にAPIを利用することが可能です。
自分たちでクライアントを作成するときはもちろん、外部の開発者やベンダにAPIを利用してもらうときにも、開発なしでSDKを提供できてしまうのは便利ですよね。

参考：APIのSDKを作成する
http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/how-to-generate-sdk.html

### エラー発生時のレスポンスの制御
SalesforceのAPI呼び出しはSalesforceのメンテナンスや障害、設定の変更など様々な理由で失敗する可能性があります。
特に、Apex RESTで独自にAPIを構築した場合、想定外のエラーが発生する可能性を0にすることは難しいかもしれません。

Salesforceでエラーが発生した場合のレスポンス内容は残念ながら統一されていません。
私もJSONが返却されることを期待しているAPIでhtmlが返却されたことがあります。

これはクライアント側からするとエラーハンドリングがとても面倒になってしまいます。
特に、モバイルアプリの開発者など、Salesforceの知識がない開発者にはコントロールが難しいでしょう。

APIGatewayではバックエンドから返された結果を特定のステータスコードとレスポンスにマッピングすることが可能です。
Salesforce側で想定外の結果が返された場でも、APIGatewayで特定のレスポンスにマッピングすることで、想定外のエラーを吸収し、
クライアントには事前に定義されたエラーのレスポンスを返却することが可能です。

これにより、クライアント側もレスポンスの内容を事前に十分予測できるので、エラーハンドリングなどの実装がしやすくなるはずです。


## APIの運用を楽にする
### アクセスコントロール
SalesforceのAPIを呼び出すには

* 接続アプリケーションの認証情報(アクセスキー、シークレットキー)
* Salesforceのユーザ

の二つが必要になります。
これらをクライアントごとに配布することも可能ですが、クライアントがどんどん増えていった場合、
その都度接続アプリケーションを登録したり、ユーザを発行する手間やライセンス費用はバカになりません。
しかも、これらの情報が何らかの理由で流出した場合、流出したものを無効化し、再発行してクライアント側に再配布もしなければなりません。

また、クライアント毎に利用可能なAPIを制限したい、という場合にはそれぞれプロファイルを作成して、それに対応したApexクラスを作ったり、、、とさらに煩雑になります。

今回の構成の場合、Salesforceへの接続情報はAPIGatewyで保持し、APIへのアクセスはAWSのIAM情報や、自作の認証/認可機構で制御することが可能になります。
クライアント側にSalesforceへの接続情報が漏れることはありませんし、万が一APIへの認証情報が流出した場合にもSalesforce側の設定を変えることなく対応が可能になります。
(例えばIAM認証の場合はIAMユーザを無効化するだけで対応ができます)

顧客の情報など貴重なデータが蓄積されているSalesforceの認証情報をクライアントに渡さないですむ、というのもとても大きいメリットかと思います。


### モニタリング
APIGatewayは他のAWSのサービスと同様、CloudWatchによる監視が可能です。
デフォルトのままでも、リクエストカウントや、レイテンシなどのメトリクスがグラフで可視化されており、
監視の条件を設定してアラートをメールやSlackに通知するということが簡単に実現できます。

## Salesforceの制約を緩和する
### キャッシュにによるガバナ制限の緩和
Salesforceはマルチテナントモデルでサービスを提供しており、あるユーザの行動が他のユーザへの悪影響を与えないよう、「ガバナ制限」が設けられています。
APIの呼び出し数にもこの制限がかかっており、具体的には下記の通りの制限があります。


| Salesforceのエディション     |       24 時間あたりの合計コール数 | 
|:-----------------|------------------:|
| Developer Edition |              15,000 |
| Enterprise Edition <br> Professional Edition (API アクセス有効)|  15,000 + (ライセンス数 X ライセンスの種類ごとのコール数)<br> ※最大 1,000,000 |  
|Unlimited Edition <br> Performance Edition | 15,000 + (ライセンス数 X ライセンスの種類ごとのコール数) |
|Sandbox| 5,000,000 

※ライセンスの種類毎のコール数など詳細は[こちら](https://developer.salesforce.com/docs/atlas.ja-jp.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_platform_api.htm)をご参照ください。

Salesforceの開発に慣れている方なら、これらを考慮した上で連携するアプリを開発するのですが、
例えばモバイルアプリの開発ベンダさんにアプリの開発を依頼し、Salesforce上のデータを操作する必要がある、
となった場合、この制限を考慮するのは難しいでしょう。

特にモバイルのような不特定多数のユーザに利用され、制御も難しいアプリの中で頻繁にAPIを呼び出すようなケースでは問題になります。

APIGatewayのキャッシュ機能を利用するとこのガバナ制限を緩和することが可能です。
APIGatewayはバックエンドからのレスポンスを最大1時間キャッシュすることができます。
キャッシュにヒットすればバックエンドを呼び出さずにレスポンスを返却しますので、SalesforceのAPI呼び出し数を消費しないでレスポンスすることが可能です。

Salesforceの最新の情報にアクセスしたい時は特定のヘッダを付与することでキャッシュを無視することもでき、柔軟な対応が可能です。

APIGatewayのキャッシュ機能についての詳細は下記をご覧ください。
http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-caching.html


## この構成のそのほかのメリット
上記以外にもAPIGatewayを利用することで

* API完成前のモックの提供(手前味噌で恐縮ですが[こちら](https://dev.classmethod.jp/cloud/aws/apigateway_mock_dev/)をご参考ください)
* バージョニング
* カナリヤリリース(re:invent17で発表された新機能!!)

などが実現できます。

# まとめ
SalesforceのアドベントカレンダーなのにAPIGatewayの説明がほとんどになってしまいました、、、
SalesforceのAPIは非常に優れたCRMやマーケティングツールの中にある貴重なデータに簡単にアクセスでき、Apexを利用すればデータに近いところで、複雑なビジネスロジックも実現できます。

ただ、Apex RESTであっても本格的なBtoCサービスで利用するようなAPIの公開、運用には少し力不足ですし、それが得意分野というわけではありません。

AWSのAPIGatewayのようにそこを得意分野とするサービスを利用することで、互いの弱点を補い合い、長所をさらに生かしてサービスが作りやすくなるのではないでしょうか。

また、IFとロジックが完全に分離するため、お互いの変更の影響範囲を局所化でき、開発やリリースがシンプルになる、ということも大きな利点です。

長くなって&文章が多くなってしまいましたが、SalesforceのAPIの前にAPIGatewayを立てた場合のメリットについて、参考になれば幸いです。
(諸々あって今日は間に合いませんでしたが、後ほどサンプル実装も公開します。別記事になるかも。)