【備忘録】SalesforceのRestAPIをまとめた

##Rest APIの実行の仕方
APIを実行するツールとしてPOSTMANやSalesforce限定だとWorkbenchなどで確認できますが、今回はcURLを使用して確認していこうと思います。

###例１：レコードの取得（GET）
例えば取引先レコードの取得は以下のように入力して cURL を実行します。

```
curl https://<Instance>.my.salesforce.com/services/data/v53.0/sobjects/Account/<RecordId> -H "Authorization: Bearer <sid>"
```

＜Instance＞：自身の組織のインスタンス名を記載します。
＜sid＞:Chromeの場合、設定=>プライバシーとセキュリティ=>Cookie と他のサイトデータの検索=>すべてのCookieとサイトデータを表示=>Cookieを検索でインスタンス名を検索してInstance.my.salesforce.comにあるsidを記載します
＜RecordId＞：対象のレコードIdを記載します。

上記を実行した場合、例えば以下のような感じになります。

```
{
  "attributes": {
    "type": "Account",
    "url": "/services/data/v53.0/sobjects/Account/<RecordId>"
  },
  "Id": "<RecordId>",
  "IsDeleted": false,
  "MasterRecordId": null,
  "Name": "UpdateRestName",
  "Type": "Customer - Direct",
  "ParentId": null,
  "BillingStreet": "525 S. Lexington Ave",
  "BillingCity": "RestBillingCity",
  "BillingState": "NC",
  "BillingPostalCode": "27215",
  "BillingCountry": "USA",
  "BillingLatitude": null,
  "BillingLongitude": null,
  "BillingGeocodeAccuracy": null,
  "BillingAddress": {
    "city": "RestBillingCity",
    "country": "USA",
    "geocodeAccuracy": null,
    "latitude": null,
    "longitude": null,
    "postalCode": "27215",
    "state": "NC",
    "street": "525 S. Lexington Ave"
  },
  "ShippingStreet": null,
  "ShippingCity": null,
  "ShippingState": null,
  "ShippingPostalCode": null,
  "ShippingCountry": null,
  "ShippingLatitude": null,
  "ShippingLongitude": null,
  "ShippingGeocodeAccuracy": null,
  "ShippingAddress": null,
  "Phone": "(336) 222-7000",
  "Fax": "(336) 222-8000",
  "AccountNumber": "CD656092",
  "Website": "www.burlington.com",
  "PhotoUrl": "/services/images/photo/<RecordId>",
  "Sic": "546732",
  "Industry": "Apparel",
  "AnnualRevenue": 350000000,
  "NumberOfEmployees": 9000,
  "Ownership": "Public",
  "TickerSymbol": "BTXT",
  "Description": "あ\r\nい\r\nう\r\nえ\r\nお",
  "Rating": "Warm",
  "Site": null,
  "OwnerId": "<OwnerId>",
  "CreatedDate": "2021-12-25T23:57:36.000+0000",
  "CreatedById": "0055h000004e9z8AAA",
  "LastModifiedDate": "2022-01-02T05:27:59.000+0000",
  "LastModifiedById": "0055h000004e9z8AAA",
  "SystemModstamp": "2022-01-02T05:27:59.000+0000",
  "LastActivityDate": null,
  "LastViewedDate": "2022-01-02T07:11:37.000+0000",
  "LastReferencedDate": "2022-01-02T07:11:37.000+0000",
  "Jigsaw": null,
  "JigsawCompanyId": null,
  "CleanStatus": "Pending",
  "AccountSource": null,
  "DunsNumber": null,
  "Tradestyle": null,
  "NaicsCode": null,
  "NaicsDesc": null,
  "YearStarted": null,
  "SicDesc": null,
  "DandbCompanyId": null,
  "CustomerPriority__c": null,
  "SLA__c": "Silver",
  "Active__c": null,
  "NumberofLocations__c": 6,
  "UpsellOpportunity__c": "Maybe",
  "SLASerialNumber__c": "5367",
  "SLAExpirationDate__c": "2021-01-19"
}
```
＊実際はすべて連結された状態でレスポンスが返されるので、見やすくするために例えば jq を導入すると上記のように見やすくなります。

###例２：まとめてレコードを取得
例えば取引先の情報をまとめて取得したい場合は以下のように入力して cURL を実行します。

```
curl https://<Instance>.my.salesforce.com/services/data/v53.0/query/?q=SELECT+name,+CreatedDate+from+Account -H "Authorization: Bearer <sid>" 
```

上記を実行した場合、例えば以下のような感じになります。

```
{
  "totalSize": 2,
  "done": true,
  "records": [
    {
      "attributes": {
        "type": "Account",
        "url": "/services/data/v53.0/sobjects/Account/<RecordId>"
      },
      "Name": "Pyramid Construction Inc.",
      "CreatedDate": "2021-12-25T23:57:36.000+0000"
    },
    {
      "attributes": {
        "type": "Account",
        "url": "/services/data/v53.0/sobjects/Account/<RecordId>"
      },
      "Name": "Dickenson plc",
      "CreatedDate": "2021-12-25T23:57:36.000+0000"
    }
  ]
}
```

###例３：レコードの更新（PATCH）
例えば取引先の情報を更新したい場合は以下のように入力して cURL を実行します。

```
curl https://<Instance>.my.salesforce.com/services/data/v53.0/sobjects/Account/<RecordId> -H "Authorization: Bearer <sid>" -H "Content-Type: application/json" -d @patchAccount.json -X PATCH
```

-d @patchAccount.json：こちらはカレントディレクトリに patchAccount.json というファイルがあるのが前提となり、このファイルは更新したい内容のボディが記載されています。

例えば以下のようなJSON形式になります。

```
{
    "Name":"CreateRestName",
    "BillingCity" : "CreateBillingCity"
}
```

###例４：レコードの作成（POST）
例えば取引先を新規作成したい場合は以下のように入力して cURL を実行します。

```
curl https://<Instance>.my.salesforce.com/services/data/v53.0/sobjects/Account -H "Authorization: Bearer <sid>" -H "Content-Type: application/json" -d @createAccount.json
```

参考：https://developer.salesforce.com/docs/atlas.ja-jp.api_rest.meta/api_rest/dome_sobject_create.htm

###例５：レコードの削除（DELETE）
例えば指定の取引先を削除したい場合は以下のように入力して cURL を実行します。

```
curl https://<Instance>.my.salesforce.com/services/data/v53.0/sobjects/Account/<RecordId> -H "Authorization: Bearer <sid>" -X DELETE
```


・コマンドの一覧（リファレンス）
https://developer.salesforce.com/docs/atlas.ja-jp.api_rest.meta/api_rest/resources_list.htm
・jq
https://stedolan.github.io/jq/

##カスタム Rest API の作り方
上記の内容で不十分な場合はカスタムで任意の Rest API も作成することができます。
複雑な処理を行いたい場合や任意のレスポンスが欲しい場合はカスタム Rest API を作成します。

例えば取引先の情報と共に商談の情報を取得する場合を考えます。

```
@RestResource(urlMapping='/getAccountInfo/*')

global with sharing class getAccountInfo {
    @HttpGet
    global static void doGet(){
        RestRequest req = RestContext.request;
        RestResponse res = RestContext.response;
        String param = req.requestURI.remove('/getAccountInfo/');     
        
        Account acct = [SELECT Id, Name, Description, NumberOfEmployees, Site, Phone, AnnualRevenue, LastModifiedDate FROM Account WHERE Id=:param];
        List<Opportunity> Opportunities = [SELECT Id, Name FROM Opportunity WHERE AccountId =:acct.Id];
        
        JSONGenerator gen = JSON.createGenerator(true);
        
        gen.writeStartObject();
        gen.writeIdField('Id', acct.Id);
        gen.writeStringField('Name', acct.Name);
        gen.writeNumberField('NumberOfEmployees', acct.NumberOfEmployees);
        gen.writeStringField('Phone', acct.Phone);
        if(String.isBlank(acct.Site)){
            gen.writeNullField('Site');
        } else {
            gen.writeStringField('Site', acct.Site);
        }
        gen.writeNumberField('AnnualRevenue', acct.AnnualRevenue);
        
        gen.writeFieldName('Opportunities');
        gen.writeStartArray();
        for(Integer i =0; i < Opportunities.size(); i++){
            gen.writeStartObject();
            gen.writeIdField('Id', Opportunities[i].Id);
            gen.writeStringField('Name', Opportunities[i].Name);
            gen.writeEndObject();    
        }
        gen.writeEndArray();
        
        gen.writeStringField('Description', acct.Description);
        gen.writeDateTimeField('LastModifiedDate', acct.LastModifiedDate);
        gen.writeEndObject();
        String strJson = gen.getAsString();
        
        res.addHeader('Content-Type', 'application/json');
        res.responseBody = Blob.valueOf(strJson);
    }
}
```

参考：https://developer.salesforce.com/docs/atlas.ja-jp.230.0.apexcode.meta/apexcode/apex_json_jsongenerator.htm

以下のように文字列を連結する形でも出来ますが、項目が増えれば増えるほどと単純ミスが発生しやすく項目に改行（\r\n）があるとうまくいかないので、基本的にJSONGeneratorを使ったほうがよいと思います。

```
String strJson ='';
strJson += '{';
strJson += '"Name" : "' + acct.Name +'"';
strJson += '}';
res.addHeader('Content-Type', 'application/json');
res.responseBody = Blob.valueOf(strJson);
```


##カスタム REST API を実行
上記を実行するには以下のように cURL を実行します。

```
curl https://<Instance>.my.salesforce.com/services/apexrest/getAccountName/<RecordId> -H "Authorization: Bearer <sid>"
```

上記の実行結果が以下の通りになります。

```
{
  "Id" : "<RecordId>",
  "Name" : "UpdateRestName",
  "NumberOfEmployees" : 9000,
  "Phone" : "(336) 222-7000",
  "Site" : null,
  "AnnualRevenue" : 350000000,
  "Opportunities" : [ {
    "Id" : "<RecordId>",
    "Name" : "test"
  }, {
    "Id" : "<RecordId>",
    "Name" : "Burlington Textiles Weaving Plant Generator"
  } ],
  "Description" : "あ\r\nい\r\nう\r\nえ\r\nお",
  "LastModifiedDate" : "2022-01-02T05:27:59.000Z"
}
```