触るまいとしていたSalesforceを触らないといけない感じに。
やりたいこと
- Heroku のサブドメインを動的に設定したい。
- Salesforce のカスタムオブジェクトにあるレコードのある項目(テキスト)を取得して、サブドメインにあてがう。
実装方針
- レコード詳細ページのカスタムボタンを押したら、ある項目の値をHeroku にあるサイトのサブドメインとして設定する。
- カスタムボタンからjavascriptを実行、Apex Class を呼び出す感じで。
- Salesforce の Apex Class から 外部のWebAPIを叩く。
- BASIC認証などで user、password など使う場合は、「カスタム設定」というところに隠し、それを使うようにする。
実装手順
- リモートサイトの設定
- カスタム設定
- Apex Class 記述
- カスタムボタンまたはカスタムリンク
- Javascriptを実行
- ページレイアウト編集
- テスト
やってみた
リモートサイトの設定
設定
>クイック検索ボックス
で「リモート」を検索>リモートサイトの設定
>新規リモートサイト
でエンドポイントのURLを登録しておく。(しないとSalesforceとエンドポイントの間でHTTPリクエストレスポンスのやりとりができない)
カスタム設定
秘匿したい情報はカスタム設定
のカスタム項目に保存できる。設定
>クイック検索ボックス
で「カスタム設定」を検索。外部WebAPIの認証に必要なAPIキーなどはここに格納し、Apex には直接APIキーなどは記述せず、カスタム項目に格納された値を参照するように記述する。
ちなみに、カスタム設定は Apex のなかではこんな感じで呼び出すらしい。
class SomeClass{ public static String someMethod(){ CustomSetting cs = CustomSetting(); String a = cs.column_a; } private class CustomSetting{ my_custom_setting__c cs = my_custom_setting__c.getInstance('user_id'); //保存先をユーザにした場合 String column_a = column_a__c; String column_b = column_b__c; String column_c = column_c__c; } }
class のなかに定義するより、外部に独自にclass定義して、他のclassからはそれを呼び出すようにする方がいいかしら。
public class Secret { public string heroku_api_key; public string dns_account; public string dns_zone_id; public string dns_api_key; public Secret() { Credential cr = new Credential(); this.heroku_api_key = cr.heroku_api_key; this.dns_account = cr.dns_account; this.dns_zone_id = cr.dns_zone_id; this.dns_api_key = cr.dns_api_key; } private class Credential{ String user_id = 'hoge'; my_custom_setting__c mc = my_custom_setting__c.getInstance(user_id); String heroku_api_key = mc.heroku_api_key__c; String dns_account = mc.dns_account__c; String dns_api_key = mc.dns_api_key__c; String dns_zone_id = mc.dns_zone_id__c; } }
Apex Class 記述
とりあえず、こんな感じでかけばいいらしい(※正常処理のみ)。下記のEndpointはテストサイト(httpbin.org)だけど、実際にはここをHeroku Platform API にする。
global class httpRequestDemo { webService static String makeGetCallout() { String result = 'hoge'; Http http = new Http(); HttpRequest request = new HttpRequest(); Blob credential = Blob.valueOf('username:password'); request.setEndpoint('https://httpbin.org/get'); request.setMethod('GET'); request.setHeader('Accept', 'application/json'); request.setHeader('Content-type', 'application/json'); request.setHeader('Authorization', 'BASIC ' + EncodingUtil.base64Encode(credential)); HttpResponse response = http.send(request); Integer status = response.getStatusCode(); if (status == 200){ result = response.getBody(); }else{ result = status.format() + response.getBody(); } return result; } }
追記;こんな感じでカスタムドメインの設定できた。コードが良くなさそうだけど、Apexがよくわからないので、どう改善したらいいものか思案中。
global class HerokuAPI { webService static String createNewDomain() { Http http = new Http(); HttpRequest request = new HttpRequest(); Credential conf = new Credential(); request.setEndpoint('https://api.heroku.com/apps/app_name/domains'); request.setHeader('Authorization', 'Bearer ' + conf.heroku_api_key); request.setHeader('Accept', 'application/vnd.heroku+json; version=3'); request.setHeader('Content-type', 'application/json'); request.setMethod('POST'); request.setBody('{"hostname": "subdomain.example.com"}'); HttpResponse response = http.send(request); Integer status = response.getStatusCode(); if (status == 200){ return '200:' + response.getBody(); }else{ return status.format() + response.getBody(); } } private class Credential{ String user_id = 'ユーザーのオブジェクトID'; credential___c cr = credential___c.getInstance(user_id); String heroku_api_key = cr.heroku_api_key__c; } }
カスタムボタンまたはカスタムリンク
カスタムボタンまたはカスタムリンク の「動作」で「Javascriptを実行」を選択し、下記のようなjsを書く。
{!REQUIRESCRIPT('/soap/ajax/36.0/connection.js')} {!REQUIRESCRIPT('/soap/ajax/36.0/apex.js')} var ret = sforce.apex.execute('HttpBinInterface','makeGetCallout',{}); alert(ret);
参考