プログラマ38の日記

主にプログラムメモです。

Salesforce: Rest API で思ったこと

SalesforceRest APIで思ったことのメモです。

 

まずSalesforceRest APIは次の特徴を持ちます。(個人的に思っていることです。。詳細な仕様はSalesforceのヘルプを参照ください)

 

  • httpsの通信ができれば、SalesforceAPIのやり取りが可能
  • APIの送受信の形式はJSON文字列かXMLか選べる
  • REST APIでのみ提供されている機能がある

 

httpsの通信ができれば、SalesforceAPIのやり取りが可能

TSL1.1以上でという制限はありますが、httpsの通信ができれば、SOAP APIのようにwsdlソースコードに展開する仕組みがなくても簡単に利用できます。

なので、VBScriptや、Excelマクロ、PowerShellInvoke-RestMethod
)から簡単に利用できます。

 

REST API以外のSalesforceAPIを利用するには、ログインURLとログイン情報(ユーザ、パスワード)を指定してログインし、ログイン後Salesforceから返却されるインスタンスURLとセッションIDを使用してメソッドをコールします。

 

REST APIでも「https://login.salesforce.com/services/oauth2/authorize?response_type=code&client_id=XXX&redirect_uri=YYY&state=mystate」というREST APIでの認証が用意されています。REST APIでの認証をするためには、コンシューマ鍵を別途設定して取得する必要があります。

 

ですが、認証後で必要な情報はセッションID(RESTではaccess_tokenという名前)とインスタンスURLなので、無理にコンシューマ鍵を用意してREST APIで認証する必要はありません。通常のSOAP APIでログインして、セッションIDとインスタンスURLを取得すればいいだけです。

APIの送受信の形式はJSON文字列かXMLか選べる

REST APIのリクエストとレスポンスの形式はJSON文字列かXMLを選べます。JSONのパーサーが利用できればJSONの方が使いやすいと思います。

デフォルトの形式はJSONですが、リクエストヘッダに「Accept: application/xml」とするか、リクエストのURLに「.xml」の拡張子をつけることでXMLに変更できます。

(URLでXMLを指定する例:https://apX.salesforce.com/services/data/v41.0/query.xml?q=~)

REST APIでのみ提供されている機能がある

SOQLやビューの実行プランはREST APIでのみ取得可能という記事を書いています。(記事内容は実行プランを取得するExcelマクロを作成したという内容です)

それ以外にも、大きなバイナリデータを取得する時は、SOAP APIよりREST APIの方が適している時があります。

静的リソース(StaticResource)、ドキュメント(Document)、添付ファイル(Attachment)は登録できるサイズが制限されているので、SOAP APIで取得できますが、ファイル(ContentVersion)やイベントログ(EventLogFile)は、サイズが大きくなってくるとSOAP APIで取得できない場合があります。

そんな時は、REST APIでバイナリデータを取得することになります。

 

例:ファイルの取得

https://apX.salesforce.com/services/data/v41.0/sobjects/ContentVersion/対象のSalesforceID/VersionData

例:イベントログの取得

https://apX.salesforce.com/services/data/v41.0/sobjects/EventLogFile/対象のSalesforceID/LogFile

 

上記のREST APIを実行すると、HTTPのレスポンスをストリームで受け取れるので大きなバイナリデータもファイルに出力することができます。

 

最後に

JavaREST APIを扱うサンプルプログラムを書いておきたいと思います。

ちょっと長いのですが、通常のhttpsの通信だけでSalesforceのファイル(ContentVersion)からファイルを取得する処理です。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;


public class RestSample {

  public static void main(String[] args) throws Exception{
    
    
    String loginendpoint = "https://login.salesforce.com/services/Soap/u/41.0";
    String loginusername = "sampleuser@sample.user";
    String loginpassword = "samplepassword";
    
    
    String loginxml =
        "<?xml version="1.0" encoding="UTF-8"?><env:Envelope                                                    " +
            "   xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"  " +
            "   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">                                                " +
            " <env:Body>                                                                                                " +
            "  <m:login xmlns:m="urn:partner.soap.sforce.com" xmlns:sobj="urn:sobject.partner.soap.sforce.com">     " +
            "   <m:username>#sfusername#</m:username>                                                                   " +
            "   <m:password>#sfpassword#</m:password>                                                                   " +
            "  </m:login>                                                                                               " +
            " </env:Body>                                                                                               " +
            "</env:Envelope>                                                                                            " ;
    
    URL url = new URL(loginendpoint);
    
    HttpURLConnection loginhttp = (HttpURLConnection)url.openConnection();
    
    loginhttp.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
    loginhttp.setRequestProperty("SOAPAction", "login");
    loginhttp.setRequestMethod("POST");
    
    
    String loginenv = loginxml.replace("#sfusername#", loginusername);
    loginenv = loginenv.replace("#sfpassword#", loginpassword);
    
    
    loginhttp.setDoOutput(true);
        OutputStreamWriter out = new OutputStreamWriter(loginhttp.getOutputStream());
        out.write(loginenv);
        out.close();
        loginhttp.connect();  
    
        final int status = loginhttp.getResponseCode();
        if (status != HttpURLConnection.HTTP_OK) {
          loginhttp.disconnect();
          throw new Exception("通信エラーが発生 ResponseCode:" +  status);
        }

          
      InputStream in = loginhttp.getInputStream();
        
        DocumentBuilder doc = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document document = doc.parse(in);
        in.close();
        loginhttp.disconnect();
        
        
        String serverURL = null;
        String sessionId = null;
        try{
          sessionId = document.getElementsByTagName("sessionId").item(0).getTextContent();
          serverURL = document.getElementsByTagName("serverUrl").item(0).getTextContent();
        } catch(Exception e){
          throw new Exception("ログインで失敗:" +  e);
        }
        
    String instanceurl = serverURL.substring(0, serverURL.indexOf("/services"));
        
        String resturl = instanceurl + "/services/data/v40.0/sobjects/ContentVersion/対象のSalesforceID/VersionData";
    HttpURLConnection resthttp = (HttpURLConnection)new URL(resturl).openConnection();
  
    resthttp.setRequestProperty("Content-Type", "application/octet-stream");
    resthttp.setRequestProperty("Authorization", ":Bearer " + sessionId);
    resthttp.setRequestMethod("GET");
    
    resthttp.connect();
    
    
    
    InputStream responseStream = resthttp.getInputStream();
    
    BufferedInputStream bStream = new BufferedInputStream(responseStream);
    
    BufferedOutputStream bFileStream = new BufferedOutputStream(new FileOutputStream("保存するファイル名"));
    
    while(true){
      int val = bStream.read();
      
      if(val == -1){
        break;
      }
      
      bFileStream.write(val);
    }
    
    bStream.close();
    bFileStream.close();
  }
}

補足ですが、ContentVersionは、自分の参照できるファイルしかアクセスできません。例えば他の人がアップロードしたファイルはシステム管理者であってもContentVersionからは取得できません。

Chatterファイルは、自分が参加しているChatterGroupであれば取得可能です。