【Salesforce】外部WebAPI使ったらExceptionエラー

# SalesforceのCallout関連エラーまとめ

Salesforceで開発をしていると、APIコールアウトを行う際に特定の制限によりエラーが発生することがあります。
本記事では、以下の3つのエラーについて原因と解決策を解説します。

---

## 1. **Callout from triggers are currently not supported.**

### **エラーの原因**
このエラーは、**トリガー（Trigger）内でHTTPコールアウトを実行しようとした場合**に発生します。Salesforceのトリガーは、同期的な処理のみが許可されており、HTTPコールアウトのような非同期処理はサポートされていません。

### **解決策**
トリガー内で直接コールアウトを行わず、非同期処理を利用します。具体的には、以下の手法が推奨されます。

1. **@futureメソッドを利用**
   ```apex
   @Future(callout=true)
   public static void callExternalAPI(String recordId) {
       // コールアウト処理
       HttpRequest req = new HttpRequest();
       req.setEndpoint('https://example.com/api');
       req.setMethod('GET');
       Http http = new Http();
       HttpResponse res = http.send(req);
       System.debug('Response: ' + res.getBody());
   }
   ```

2. **Queueableクラスを利用**
   ```apex
   public class CalloutQueueable implements Queueable, Database.AllowsCallouts {
       private String recordId;
       public CalloutQueueable(String recordId) {
           this.recordId = recordId;
       }
       public void execute(QueueableContext context) {
           HttpRequest req = new HttpRequest();
           req.setEndpoint('https://example.com/api');
           req.setMethod('GET');
           Http http = new Http();
           HttpResponse res = http.send(req);
           System.debug('Response: ' + res.getBody());
       }
   }
   ```

   **トリガーからの呼び出し例**:
   ```apex
   System.enqueueJob(new CalloutQueueable(record.Id));
   ```

---

## 2. **Callout not allowed from this future method. Please enable callout by annotating the future method.**

### **エラーの原因**
このエラーは、**@futureメソッドに`callout=true`のアノテーションが付与されていない場合**に発生します。`@future`メソッドでHTTPコールアウトを実行する場合、明示的に`callout=true`を指定する必要があります。

### **解決策**
@futureメソッドでAPIコールアウトを行う場合は、以下のように`@Future(callout=true)`を使用します。

```apex
@Future(callout=true)
public static void callExternalAPI(String recordId) {
    HttpRequest req = new HttpRequest();
    req.setEndpoint('https://example.com/api');
    req.setMethod('GET');
    Http http = new Http();
    HttpResponse res = http.send(req);
    System.debug('Response: ' + res.getBody());
}
```

**注意**: @futureメソッドでは複数のパラメータを渡せないため、必要なデータはSObject IDやJSON文字列などに変換して渡します。

---

## 3. **Callout from scheduled Apex not supported.**

### **エラーの原因**
このエラーは、**スケジュールされたApex（Schedulableクラス）内で直接HTTPコールアウトを実行しようとした場合**に発生します。スケジュールジョブはコールアウトをサポートしていないため、この制限によりエラーとなります。

### **解決策**
スケジュールジョブでAPIコールアウトを行う場合は、以下のいずれかの手法を利用します。

1. **@futureメソッドを呼び出す**
   ```apex
   global class ScheduledJob implements Schedulable {
       global void execute(SchedulableContext context) {
           MyFutureClass.callExternalAPI();
       }
   }

   public class MyFutureClass {
       @Future(callout=true)
       public static void callExternalAPI() {
           HttpRequest req = new HttpRequest();
           req.setEndpoint('https://example.com/api');
           req.setMethod('GET');
           Http http = new Http();
           HttpResponse res = http.send(req);
           System.debug('Response: ' + res.getBody());
       }
   }
   ```

2. **Queueableクラスを利用**
   スケジュールジョブ内でQueueableクラスを呼び出します。
   ```apex
   global class ScheduledJob implements Schedulable {
       global void execute(SchedulableContext context) {
           System.enqueueJob(new CalloutQueueable('recordId'));
       }
   }
   ```

---

## まとめ

| **エラー**                                   | **原因**                                                                                 | **解決策**                                                                                                           |
|---------------------------------------------|-----------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|
| Callout from triggers are currently not supported. | トリガー内で直接コールアウトを実行                                                       | @futureメソッドまたはQueueableクラスを使用                                                                           |
| Callout not allowed from this future method. | @futureメソッドで`callout=true`を指定していない                                           | @futureメソッドに`@Future(callout=true)`アノテーションを追加                                                         |
| Callout from scheduled Apex not supported.  | スケジュールジョブ内で直接コールアウトを実行                                             | @futureメソッドまたはQueueableクラスを利用                                                                          |

これらの制限を理解し、適切な非同期処理を実装することで、Salesforceの開発を効率的に進めることが可能です。