【SF】クラウドサインAPI連携 ～基本仕様・トークン取得～

# 目次
1. クラウドサインAPI連携 ～基本仕様・トークン取得～  ← ★ここ
2. クラウドサインAPI連携 ～テンプレート取得・更新～
3. クラウドサインAPI連携 ～宛先選択～
4. クラウドサインAPI連携 ～入力項目埋め込み～
5. クラウドサインAPI連携 ～書類送信～
6. クラウドサインAPI連携 ～ファイル保存～
7. クラウドサインAPI連携 ～ステータス更新～

# はじめに
Salesforceとクラウドサインの連携をApexで実装したので、自身の振り返りも含めて記事にしました。
実装した内容を切り分けると、

- トークン取得
- テンプレート書類の取得、更新
- 宛先の選択
- 入力項目の埋め込み
- 書類の送信
- ファイルの保存
- 書類ステータスの更新

上記が全てSalesforce上で行えるようになっています。
テスト開発の段階であること・私自身がApexの使用経験に乏しいことから、クラス設計や実装方法に至らない点もあるかと思いますが、その際はご容赦下さい。

それでは、複数記事に跨りますがお付き合い下さい！

# 画面遷移

①テンプレート選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573865/f334689b-f98c-0b11-d499-039cfc40e806.png)
②送信先選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573865/53ee2d0a-5cef-9da5-15a6-fda019b8f015.png)
③入力項目編集
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573865/3fbd44a0-c78d-d543-afe0-48caeb73d812.png)
④書類確認・送信
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573865/e783e0c9-aaea-c038-9ca7-c1058939e66e.png)

# クラウドサインの基本仕様
##### 参考資料
 - [クラウドサイン](https://www.cloudsign.jp/)
 - [クラウドサイン Web API 利用ガイド](https://help.cloudsign.jp/ja/articles/2681259-%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%82%B5%E3%82%A4%E3%83%B3-web-api-%E5%88%A9%E7%94%A8%E3%82%AC%E3%82%A4%E3%83%89)
 - [cloudsign-web_api | 0.14.1 | CloudSign | SwaggerHub](https://app.swaggerhub.com/apis/CloudSign/cloudsign-web_api/0.14.1)

##### 書類の管理構造について
- `documents` → 1送信あたりの書類全体を指す
- `participants` → documentsの1階層下に位置し、送信者を含む関係者情報を管理
- `files` → documentsの1階層下に位置し、ファイルを管理。SFにPDFを保存する際はこのファイル単位
- `widgets` → filesのの1階層下に位置し、入力項目（項目の種類・ラベル・位置・割り当てられた関係者情報など）を管理する。
- `templates` → クラウドサイン上に保存されているテンプレート。構造はdocumentsと同様で、宛先や入力項目の情報を管理する。

##### APIでの書類送付～ステータス取得までの流れ

1. `POST/token` → クライアントID(クラウドサイン管理画面から発行可)を送信し、アクセストークンを取得。取得後1時間有効、コールアウトの際は毎回送信が必要
2. `POST/documents`（書類の作成） → タイトル・テンプレ－トなどを選択して作成する。
   この時点では宛先情報などは設定できず、あくまで一度下書き保存するのみ。  
3. `PUT/documents/participants` → participants毎に名前やアドレスを設定
4. `PUT/documents/files/widgets` → widgets毎に入力項目（入力する担当者・入力形式・ラベル・位置）を設定
5. `POST/documents` → documentIDを付与してPOSTすることで、下書き状態のdocumentを送信できる
6. `GET/documents/files` → filesをPDF形式で取得
7. `GET/documents` → （必要なタイミングで）書類の情報を取得し、書類ステータスを更新。テンプレート情報の取得も同様

# 事前準備など
### クラウドサイン側
- クライアントIDの発行
- 書類テンプレートの作成（入力項目の配置を含む）

### Salesforce側
- ユーザのカスタム項目に「クライアントID」を作成、保存しておく
- 「書類の管理構造」で挙げた5つのカスタムオブジェクト・カスタム項目・リレーションを作成
- `documents`に`Account`への主従関係を作成
- 書類送付の宛先は`Contact`からメールアドレスを取得する想定
- リモートサイトの登録（本番 → `https://api.cloudsign.jp`・sandbox → `https://api-sandbox.cloudsign.jp`）

以上で準備完了です！

# トークン取得

```apex
public with sharing class SendCloudsignDocumentController {
    public Account act;
    public String endpoint;
    public String accessToken;
    public User currentUser = [SELECT Id, Name, CloudSigin_id__c FROM User WHERE Id = :UserInfo.getUserId() LIMIT 1];
    public String clientId = currentUser.CloudSigin_id__c;

    public SendCloudsignDocumentController(ApexPages.StandardController controller){
        this.act = (Account)controller.getRecord();
        this.endpoint = 'https://api-sandbox.cloudsign.jp/';
        this.accessToken = GetCloudsignToken.callApi(clientId, endpoint);
    }
}
```

```apex
global with sharing class GetCloudsignToken {
    global static String callApi(String clientId, String endpoint) {
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint(endpoint + 'token');
        request.setMethod('POST');
        request.setHeader('Content-Type', 'application/x-www-form-urlencoded');
        request.setBody('client_id=' + clientId);
        HttpResponse response = http.send(request);

        String accessToken;
        Integer statusCode = response.getStatusCode();
        if(statusCode == 200) {
            Map<String,Object> results = (Map<String,Object>)JSON.deserializeUntyped(response.getBody());
            accessToken = 'Bearer ' + (String)results.get('access_token');
        } else {
        System.debug('Error : ' + statusCode + ' => ' + response.getBody());
        }
        return accessToken;
    }
}
```

クラウドサインAPIを利用する際は、初めにアクセストークンを取得する必要があります。
処理を行う際にはそのトークンを毎回送信する必要があるため、コントローラーで値を保持しておきます。

1. 基本情報の取得
    - Account  
    Accountページにアクションボタンを設置する想定なので、コンストラクタ内で`(Account)controller.getRecord()`と記載してAccountレコードを取得
    - currentUser  
    SOQLに`WHERE Id = :UserInfo.getUserId() LIMIT 1`と記載してUser情報を取得（LIMIT 1と記載しないと返り値がList型になるため注意）
2. コールアウト  
   - 送信先 → `https://api-sandbox.cloudsign.jp/token`
   - メソッド → `POST`
   - body → クライアントID  
   細かい仕様は[SwaggerHub](https://app.swaggerhub.com/apis/CloudSign/cloudsign-web_api/0.14.1)でテストすれば確認できます。
3. レスポンス  
   JSON型のレスポンスは、基本的に`Map<String,Object>`で受ければ問題ありません。  
   トークン送信時は`Authorization: Bearer`ヘッダを使用するため、`accessToken`に`Bearer`を含めています。

以上の処理の結果、コントローラーの`accessToken`に値を入れることができたので、これ以降の処理時に使い回せるようになりました。

今回は前置きが長かったのでここまで。
次回はテンプレートの取得・更新処理について書く予定です。