Salesforce開発入門 Vol.4 ～Apexで実装したエンドポイントへ外部から接続設定編～

こんにちは！
LIFULLエンジニアの吉永です。

前回の記事に引き続き、直近でSalesforce Service Cloud（以降SFSCと略称します）関連の開発を行っているので、今回はApexを使ってカスタムオブジェクトへのCRUD操作を行うREST APIエンドポイント実装時の外部からの接続設定の流れを紹介したいと思います。
前回の記事は[こちら](https://qiita.com/YoshinagaYuta/items/96d514128a274c83b41b)

## アプリケーションマネージャ

SFSCでApexで作成したエンドポイントへ外部から接続するには、アクセストークンを事前に発行し、エンドポイントへのリクエスト時にそのアクセストークンを含める必要があります。
なので、まずはSFSC管理画面からアクセストークンを発行する為の設定を行っていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/565820ed-7448-7584-3378-573b9e6c1e05.png)
SFSCのホーム画面のクイック検索に[アプリケーション]と入力し、アプリケーションマネージャをクリックします。
そして表示されたアプリケーションマネージャ画面の右上の[新規接続アプリケーション]をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/0dbb5b41-97e3-6299-a05b-af9ea5783ad5.png)
基本情報の接続アプリケーション名、API参照名を第三者からみて分かりやすい名称を付けます。
今回は例として、[MY注文アクセスAPI]と[MY_ORDER_ACCESS_API]にしました。
そして、取引先責任者に自分のSFSCユーザーのメアドを入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/38f0c537-f200-8c7e-ebd6-7b577c4e6e2e.png)
API (OAuth 設定の有効化)欄で、OAuth設定の有効化のチェックを入れます。
コールバックURLは今回使用しないのですが、必須項目なので`https://login.salesforce.com/`という値をひとまず入力しておきます。
選択したOAuth範囲では利用可能なOAuth範囲の中から`APIを使用してユーザデータを管理（api）`を選択して、追加ボタンを押し、選択した
OAuth範囲へ移動させます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/442cfdf1-5b08-953d-e8e4-3a37c2c7210d.png)
Webサーバフローの秘密が必要にチェックが入っていること、更新トークンフローの秘密が必要のチェックが外れていることを確認します。
その他の設定はデフォルトのままで構わないので、保存を押します。

## プロファイル

続いて、作成したアプリケーションへの接続許可をプロファイルに対して行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/c0b8ae39-2d21-3f11-a77d-fa103a8f16a7.png)
まず自分のプロフィルを調べる為に、ホーム画面の右上のアイコンをクリックします。
表示されたメニュー内のアイコンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/b4a419c6-de6b-c852-3ed1-7e0ba01fa62b.png)
ユーザーの詳細をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/b24dd34c-f781-33dc-c48b-defdce8a5f0b.png)
自分のプロファイルが確認できますので、プロファイル名を控えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/155ef12d-d9e1-1a40-a6f8-75144f2f3232.png)
ホーム画面のクイック検索にプロファイルと入力して、プロファイルをクリックします。
表示されたプロファイル一覧から自身のプロファイルを探し、編集ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/af8d2562-a4e7-3bf2-3f64-531727eb4cbf.png)
接続アプリケーションへのアクセス欄から[MY注文アクセスAPI]にチェックを入れ、保存します。

## アクセストークンの取得確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/7f61ab32-3abc-477c-b079-c72be4ada1a7.png)
ホーム画面のクイック検索にアプリケーションと入力し、アプリケーションマネージャーをクリックします。
MY注文アクセスAPI横の下向きの三角のアイコンをクリックし、表示されるメニューの参照を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/86a6a52c-33b2-82f6-b2e1-04e1c6c841cf.png)
コンシューマー鍵とコンシューマの秘密をそれぞれ控えます。
※コンシューマの秘密はクリックすると表示されます。

下記のcurlコマンドを実行します。

```bash
curl -i -X POST \
-H 'X-PrettyPrint: 1' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id={コンシューマー鍵}' \
--data-urlencode 'client_secret={コンシューマの秘密}' \
--data-urlencode 'username={SFSC自身のユーザー名}' \
--data-urlencode 'password={SFSC自身のパスワード}' \
https://{テスト用の自身のSFSCの識別名}.my.salesforce.com/services/oauth2/token
```

成功すると下記のようなレスポンスが得られるので、接続設定は完了です。

```json
{
  "access_token" : "*****",
  "instance_url" : "*****",
  "id" : "*****",
  "token_type" : "Bearer",
  "issued_at" : "*****",
  "signature" : "*****"
}
```

### レスポンスがエラーの場合

もし下記のようなエラーレスポンスの場合はパスワードに加えて、セキュリティトークンが必要な可能性もあります。

```json
{
  "error" : "invalid_grant",
  "error_description" : "authentication failure"
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/2cd8c166-54d5-d8b9-44e4-bfab710faa01.png)
ホーム画面のクイック検索にユーザと入力して、ユーザーをクリックし、表示されたユーザー一覧から自分の名前の個所をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/bc77740b-ab2f-bc32-ba58-779b164926eb.png)
ログイン履歴を確認し、`失敗: API セキュリティトークンが必要です`となっているならば、セキュリティトークンを取得します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/7c3c25c2-fa70-f8a2-5083-f23a48f32d7a.png)
ホーム画面右上のアイコンをクリックし、表示されるメニューの設定をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690018/14bcda83-6326-3eac-aa95-21f2cd74aff2.png)
左メニューから私のセキュリティトークンのリセットをクリックし、セキュリティトークンのリセットを押します。
リセット後はメールでセキュリティトークンが通知されるので、そのトークンを控えます。

curlコマンドのパスワードとセキュリティトークンを連結させた文字列で再度アクセスを試みます。

```bash
curl -i -X POST \
-H 'X-PrettyPrint: 1' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id={コンシューマー鍵}' \
--data-urlencode 'client_secret={コンシューマの秘密}' \
--data-urlencode 'username={SFSC自身のユーザー名}' \
--data-urlencode 'password={SFSC自身のパスワード}{セキュリティトークン}' \
https://{テスト用の自身のSFSCの識別名}.my.salesforce.com/services/oauth2/token
```

### アクセストークンのはまりポイント

#### 別の環境のアクセストークンを取得してしまう。

SFSCは本番環境といくつかのSandbox環境とで運用されていることが多いと思います。
例えば本番が`https://hoge.my.salesforce.com/`のようなURLの場合、Sandbox名がdevelopだとすると、SandboxのURLは`https://hoge--develop.my.salesforce.com/`のようになっており、この時Sandboxへログインする時のユーザー名は本番のユーザー名の末尾にSandbox名を追加したものになっているかと思います。

```
本番のユーザー名：yoshinaga@hoge.com
Sandboxのユーザー名：yoshinaga@hoge.com.develop
```

このような状態の時、アクセストークンを取得するcurlを例えば下記のようにしても、

```bash
curl -i -X POST \
-H 'X-PrettyPrint: 1' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id={コンシューマー鍵}' \
--data-urlencode 'client_secret={コンシューマの秘密}' \
--data-urlencode 'username=yoshinaga@hoge.com' \
--data-urlencode 'password={SFSC自身のパスワード}{セキュリティトークン}' \
https://hoge--develop.my.salesforce.com/services/oauth2/token
```

ユーザー名が本番のユーザー名だと本番環境のアクセストークンとして取得してしまうようです。

```json
{
  "access_token" : "*****",
  "instance_url" : "https://hoge.my.salesforce.com/",
  "id" : "*****",
  "token_type" : "Bearer",
  "issued_at" : "*****",
  "signature" : "*****"
}
```

上記のようにJSON内の`instance_url`が意図したURLになっているか？を確認しないとアクセストークンは取得出来ているのに、接続したい環境のAPIに取得したアクセストークンを含めても、無効とはねられてしまいます。
なので、アクセストークンをSandbox環境などで取得する際はユーザー名に注意し、レスポンスの`instance_url`が目的のSandboxになっているかを確認するようにした方がいいです。
※もしかしたら、これは弊社のSFSCの運用方法固有のものなのかもしれませんが、ご参考まで。

#### Sandboxをリフレッシュするとコンシューマー鍵とコンシューマの秘密もリセットされる

Sandboxで開発を進め、本番へ反映した後、またSandboxで開発をする前には、本番から各種設定をコピーしたSandboxを作ると思いますが、その際にコンシューマー鍵とコンシューマの秘密はリセットされて、まったく別の値に変わるので注意が必要です。
ある日突然develop環境のアプリケーションからSandboxのSFSCへ接続できなくなった場合は、Sandboxのアプリケーション設定でコンシューマー鍵とコンシューマの秘密を確認するようにしてください。

## 自身で作成したApex REST APIエンドポイントへのアクセス

下記のcurlコマンドを実行します。

```bash
curl -i -X GET -H "Content-Type: application/json" \
-H 'X-PrettyPrint: 1' \
-H 'Authorization: Bearer {取得したアクセストークン}' \
https://{テスト用の自身のSFSCの識別名}.my.salesforce.com/services/apexrest/myorder/Order0001
```

成功すると[以前の記事の動作確認のレスポンス](https://qiita.com/YoshinagaYuta/items/2ba170a89fc7bf122774#get%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E6%AD%A3%E5%B8%B8%E7%B3%BB%E7%A2%BA%E8%AA%8D)と同じようなJSONが確認できると思います。
これで、自身で作成したApexのREST APIエンドポイントへの接続確認は完了です。

### エラーレスポンスの場合

```json
[
	{
		"message": "Session expired or invalid",
		"errorCode": "INVALID_SESSION_ID"
	}
]
```

上記のようなエラーレスポンスの場合は取得したアクセストークンが期限切れか、コピペに失敗している可能性もあるので、再取得してみるなどを試してみてください。

## まとめ

いかかでしたでしょうか。
今回は自身で作成したREST APIエンドポイントへ外部から接続する為の各種設定と、実際に接続するまでの流れを解説しました。
実際にはSFSCは権限設定などが非常に複雑なので、プロファイルやアプリケーション設定のログインを許可するIPアドレスレンジ設定なども考慮しないといけないので、本番環境に適用するには考慮すべき個所は多々残っております。
ただ、外部から接続する際の設定手順を覚えることで、追加で必要になる各種権限設定は追って検討、キャッチアップするというアプローチでも良いとは思うので、そのような方の参考に本記事がなると幸いです。

最後までご覧いただき、ありがとうございました。
それではまた次の記事でお会いしましょう。