Apexから外部サービスを利用するための方法としてApexコールアウトというのがあります。
今回はこれを使って、GitHubと連携するサンプルを作ってみたという話。
Salesforceでケースが新規作成された時に、指定したGitHubのリポジトリにIssueも登録されるというもの。
(2014/06/23追記)
すごく基本的なところを勘違いしていたんですが、
HttpRequest
で外部サービスを利用するだけならApexコールアウトじゃなくていい んですね。
以下は、トリガから呼ばれる場合など、非同期処理として実行する場合 だと考えてください。
(参考)
- apex - HTTP Callout from Triggers - Salesforce Stack Exchange
- deferloader – 株式会社ウフル技術ブログ
- http://www30304u.sakura.ne.jp/blog/?p=580
リストにカスタムボタンを設置しておいて、押したら外部サービスのREST APIを実行して...とかであれば
普通のクラス内でHttpRequest
使えばいいです。
ポイント
- 連携する外部サービスのURLは「リモートサイトの設定」で設定しておく
(追記:トリガの場合は) Apexコールアウトを実装するメソッドには
@future (callout=true)
アノテーションをつけ、メソッドはstatic
にする@future
アノテーションをつけたメソッドは引数にプリミティブ型(またはプリミティブ型の配列やコレクション)しか渡せない
(SObject
やObject
を渡すことができない)
ソースコード
GitHubに公開してあります。
https://github.com/zaki-yama/force_com/tree/master/case2issue
実装してみる
リモートサイトの設定をする
Apexコールアウトでアクセスする外部WebサービスのURLは事前にSalesforce上で設定しておく必要がある。
管理 > セキュリティのコントロール > リモートサイトの設定
から、「新規リモートサイト」を選び、「リモートサイトのURL」に
https://api.github.com
を指定する。
(リモートサイト名は分かりやすい名前をつければOK)
トリガクラス
before insert
トリガを実装する。
トリガ本体にはロジックを書かず、ハンドラで処理する。
CaseTrigger.trigger
trigger CaseTrigger on Case (before insert) { if (Trigger.isBefore && Trigger.isInsert) { CaseTriggerHandler.handleBeforeInsert(Trigger.new); } }
CaseTriggerHandler.cls
public class CaseTriggerHandler { public static void handleBeforeInsert(List<Case> caseList) { for (Case c : caseList) { System.debug(LoggingLevel.INFO, 'target case:' + c); Map<String, String> request = new Map<String, String> { 'title' => '[' + c.priority + ']' + c.subject, 'body' => c.description }; Case2IssueController.createIssue(request); } } }
Case2IssueControllerがApexコールアウトを行う今回のメインのクラス。
また、引数にそのままcaseList
を渡さずにわざわざMapを作成している理由は後述。
Apexコールアウトを行うクラス
まず、コードがこちら。
public class Case2IssueController { private static String USER_NAME = '*****Your GitHub username here*****'; private static String PASSWORD = '*****Your GitHub password here*****'; private static String REPO_NAME = '*****Your GitHub repository name here*****'; @future (callout=true) public static void createIssue(Map<String, String> request) { HttpRequest req = new HttpRequest(); req.setMethod('POST'); // Set Callout timeout // default: 10 secs(that often causes "System.CalloutException: Read timed out") req.setTimeout(60000); // Set HTTPRequest header properties req.setHeader('Connection','keep-alive'); req.setEndpoint('https://api.github.com/repos/' + USER_NAME + '/' + REPO_NAME + '/issues'); // Basic Authentification Blob headerValue = Blob.valueOf(USER_NAME + ':' + PASSWORD); String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue); req.setHeader('Authorization', authorizationHeader); // Set HTTPRequest body req.setBody(JSON.serialize(request)); Http http = new Http(); try { // Execute Http Callout HTTPResponse res = http.send(req); System.debug(LoggingLevel.INFO, res.toString()); System.debug(LoggingLevel.INFO, 'STATUS:' + res.getStatus()); System.debug(LoggingLevel.INFO, 'STATUS_CODE:' + res.getStatusCode()); System.debug(LoggingLevel.INFO, 'BODY:' + res.getBody()); } catch(System.CalloutException e) { // Exception handling goes here.... System.debug(LoggingLevel.INFO, e); } } }
GitHubの認証はとりあえず簡単なものをということでBasic認証を使ってます。
それ以外の認証方式についてはここを参考に。
GitHub REST API - GitHub Docs
以下、実装上気をつける点がいくつか。
まず、Apexコールアウトを行うクラスは@future (callout=true)
アノテーションが必要。
アノテーションをつけずにトリガハンドラ内で直接実行したりすると、以下のエラーが発生する。
System.CalloutException: Callout from triggers are currently not supported
また、@future
アノテーションをつけたメソッドの引数に
List<Case> caseList
とかをそのまま渡そうとすると、コンパイルエラーになります。
classes/Case2IssueController.cls -- Error: Unsupported parameter type LIST<Case>
これについては
ここを見ると、次のように書いてある。
The specified parameters must be primitive data types, arrays of primitive data types, or collections of primitive data types. Methods with the future annotation cannot take sObjects or objects as arguments.
つまり、プリミティブ型またはその配列やコレクションしか認めていないということですね。
試してみる
Salesforceからケースを作成してみる。
登録されてます!
というわけで、実装方法で注意しないといけない部分はあるものの、比較的簡単に外部サービスと連携できました。
リファレンス
HttpRequestクラス http://www.salesforce.com/us/developer/docs/dbcom_apex250/Content/apex_classes_restful_http_httprequest.htm
HttpResponseクラス Salesforce Developers
Caseクラス Salesforce Developers
GitHub API v3 Issues - GitHub Docs
公式ドキュメントなんだけど、あまり情報が載ってない
https://developer.salesforce.com/page/JP:Apex_Web_Services_and_Callouts#HTTP_.28RESTful.29_Services
以下は技術ブログ
deferloader – 株式会社ウフル技術ブログ