REST Apex サービスのAPI定義書の作成メモ

REST Apexサービスを作成する機会があったので、健忘録として記事に起こします。
社内システムの連携を想定しています。

コーディングについてはこちらに記事を作成しました。→[[Salesforce] カスタムREST APIをApexで作成する | Qiita](https://qiita.com/TaaaZyyy/items/336ba4c49e112c08534c)

# API定義書
### ■ 基本情報
|項目|値|
|--:|:--|
|IF名|○○連携|
|FROM|○○システム|
|TO|Salesforce|
|タイミング|随時|
|メソッド|POST|
|URI|`https://マイドメイン.my.salesforce.com/services/sample/`|
|概要|APIの概要を記述|

#### 補足
* 下記のメソッドがサポートされます。
    * `GET` ― リソースを取得する
        * 情報を取得するために用いられます。サーバー上のリソースが変更される場合は原則使用しません(既読や参照日時等を除く)。 
    * `POST` ― リソースを作成する
        * ユーザ登録や記事投稿など、新しい情報を登録するために利用されます。リソースの更新にはPUT、PATCHを使います。
    * `PUT` ― リソースを作成・更新する 
        * URIで指定したリソースを更新します。もともとのリソースを完全に上書きするときに使用します。リソースの一部を更新する場合はPATCHを使用します。URIで指定したリソースが存在しない場合は新規作成しますが、データの修正にPUTをつかい、新規に作成する場合にPOSTを使用するのが一般的です。
    * `PATCH` ー リソースの一部変更(Winter'21)
        * リソースの一部を更新するときに用いられます。
    * `DELETE` ― リソースを削除する
        * URIで指定したリソースを削除するために用いられます。
* URIについて
    * URLは小文字のみで表現するようにします。単語を繋げる必要があるときはハイフンまたはアンスコで区切りますが、そもそも単語を繋ぎ合わせることは極力避けます。
    * エンドポイントの設計では複数形の名詞を使用して「リソースの集合」を表します。
    * エンドポイントに動詞は極力使用しません。操作はメソッド(GET,POST,PUT,DELETE)で表します。
        * メソッドで表現しづらい動詞はエンドポイントに追加する例もあります
    * URIはどんな機能を持つURIなのかがわかるような設計を心がけます。
        * 例: データを検索する時1 `GET contacts?q=`
        * 例: データを検索する時2 `GET accounts?country=US`
        * 例: 特定のデータを取得する時 `GET contacts/{レコードを指定するコード}`
        * 例: Aに関連するBを取得する時 `GET contacts/{レコードを指定するコード}/cases?q=`
        * 例: 新しいデータを登録する時 `POST contacts`
        * 例: データを更新する時 `PUT contacts/{レコードを指定するコード}`
        * 例: 特定のデータを削除する時 `DELETE contacts/{レコードを指定するコード}`
    * 検索・ソート・フィルタはリクエストパラメータで行います。
        * 例: 文字列hogeを含み、作成日時で降順、連絡拒否がfalse `contacts?q=hoge&sort=-createddate&optout=false`

### ■ リクエストヘッダ
|No|項目名|必須|値|備考|
|:-:|:--|:-:|:--|:--|
|1|Authorization|○|Bearer xxxxx|xxxxxはアクセストークン|
|2|Content-Type|○|application/json|固定値|

#### 補足
* GET、DELETEはリクエストボディがないためContetn-Typeを設定しません。
* POST、PUTではXMLよりJSONを使うようにします。現在APIの主流はJSONとなっているようです。
    * XMLを使用する場合は、Content-Typeを`application/xml`にします。

### ■ リクエストボディ
|No|項目名|属性|最大バイト数|必須|値|備考|
|:-:|:--|:--|:-:|:--|:--|:--|
|1|name|String|255|○|商品名||
|2|quantity|Integer|5|○|数量(0～99999)||

#### 補足
* GET、DELETEはリクエストボディは有りません。
* APIを公開する前に、項目名はよく確認すること。特に大文字小文字。

### ■ ステータスコード
|No|ステータス|備考|
|:-:|:--|:--|
|1|200|正常応答|
|2|400|クライアント起因のエラー|
|3|500|サーバーエラー|

#### 補足
* Salesforce標準のステータスコードは[こちら](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_methods_system_restresponse.htm#apex_System_RestResponse_statusCode)。

### ■ レスポンスヘッダ
|No|項目名|必須|値|備考|
|:-:|:--|:-:|:--|:--|
|1|Content-Type|○|application/json;charset=UTF-8|固定値|

#### 補足
* レスポンスの形式は極力XMLよりJSONを選択します。
    * XMLを使用する場合は、Content-Typeを`application/xml`にします。

### ■ レスポンスボディ(200)
|No|項目名|和名|属性|最大バイト数|値|sf項目名|sfラベル名|
|:-:|:--|:--|:--|:--|:--|:--|:--|:--|
|1|name|顧客名|String|255||Account.Name|顧客名|
|2|lastContactDate|最終活動日|String|10|yyyy-MM-dd形式|Account.LastContactDate__c|最終活動日|
|3|customers|取引先責任者リスト|List(Object)|-|対象がない場合は空のリスト|Account.Contacts|取引先責任者|
||>>customerCode|顧客番号|String|8||Contact.CustomerCode__c|顧客番号|
||>>Name|取引先責任者名|String|80||Contact.Name|取引先責任者名|

#### 補足
* null(`null`)と空文字(`''`)は区別するようにします。
* 日付と日時はISO-8601の拡張形式で表現するようにします。
    * `2020-11-01`
    * `2020-11-01T10:00:00.000+09:00`
* 項目名は、JSONなのでキャメルケースをが自然な気がしますが、スネークケースを採用しているAPIも多いので、どちらでも良さそうです。
* APIを公開する前に、項目名はよく確認すること。特に大文字小文字。
* レスポンスデータは極力階層化しないようにします。

### ■ レスポンスボディ(エラー)
|No|項目名|和名|属性|最大バイト数|値|備考|
|:-:|:--|:--|:--|:--|:--|:--|
|1|||List(Object)||||
||>>errorCode|エラーコード|String|255|||
||>>message|エラーメッセージ|String|255|||


# OAuth認証
API設計書にOAuthの認証方法も追記します。ここでは例として「OAuth2.0 JWT ベアラーフロー」を使用します。

### ■ 基本情報
|項目|値|
|--:|:--|
|認証方式|OAuth2.0 JWT ベアラーフロー|
|メソッド|POST|
|URL|`https://マイドメイン.my.salesforce.com/services/oauth2/token`|
|備考|① 予め自己署名デジタル証明書(.crt)をSalesforceにアップロードする必要があります。<br>② API利用時に、リクエストヘッダーに`Authorization: Bearer レスポンスのaccess_tokenの値`を追加してください。Bearerとアクセストークンの間に半角スペースが必要です。|

#### 補足
REST APIを使用するには、接続アプリケーションのOAuth範囲に`api, refresh_token, offline_access`が必要です

### ■ リクエストヘッダ
|No|項目名|必須|値|備考|
|:-:|:--|:-:|:--|:--|
|1|Content-Type|○|`application/x-www-form-urlencoded`|固定値|

### ■ リクエストボディ
|No|項目名|属性|最大バイト数|必須|値|備考|
|:-:|:--|:--|:-:|:--|:--|:--|
|1|grant_type|String|-|○|`urn:ietf:params:oauth:grant-type:jwt-bearer`|固定値|
|2|assertion|String|-|○|JWTの値を設定||

### ■ JWT
|領域|項目|値|備考|
|--:|--:|:--|:--|
|ヘッダー|alg|RS256|固定値|
|ペイロード|iss|xxxxx|接続アプリケーションのコンシューマ鍵|
|ペイロード|aud|`https://login.salesforce.com`|固定値|
|ペイロード|sub|`sample@example.com`|Salesforceユーザ名|
|ペイロード|exp|`1333685628`|Oauth トークンの有効期限。UTC で測定された 1970-01-01T0:0:0Z からの秒数として表記。現在時刻から3分間のみ有効。|

### ■ レスポンス
|No|項目名|説明|
|:-:|:--|:--|
|1|access_token|OAuth トークン|
|2|instance_url|ユーザの組織のインスタンスを示す URL|
|3|id|ユーザを識別し、ユーザの詳細を照会するために使用できる ID URL|
|4|token_type|固定値「Bearer」|
|5|scope|範囲値のスペース区切りのリスト|


# 参考
* WEB
    * [翻訳: WebAPI 設計のベストプラクティス | Qiita](https://qiita.com/mserizawa/items/b833e407d89abd21ee72)
    * [GoogleのWebAPI設計とWebAPI設計のベストプラクティスを比較してみる | Qiita](https://qiita.com/howdy39/items/3b2b14ce73ec44c54f7b)
    * [5.1. RESTful Web Service | TERASOLUNA Server Framework for Java (5.x) Development Guideline](http://terasolunaorg.github.io/guideline/5.6.0.RELEASE/ja/ArchitectureInDetail/WebServiceDetail/REST.html)
    * [OAuth 2.0 JWT Bearer Flow for Server-to-Server Integration | SALESFORCE HELP](https://help.salesforce.com/articleView?id=remoteaccess_oauth_jwt_flow.htm&type=5)
* 書籍
    * [Web API: The Good Parts (水野 貴明) | Amazon](https://www.amazon.co.jp/dp/4873116864/)