PostmanからSalesforceのToolingAPIを使ってみる *

[Postmanのまとめに戻る](https://qiita.com/Keiji_otsubo/items/84098dc24465d5787ea6)


+ [【お題】一括変更:選択リスト値項目の順番変更](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007SrHQD)

データ型が選択リスト値の項目がありまして、リスト値の数が200くらいあるものを五十音順に変更しようと思っています。漢字・アルファベットが混在するリストなので文字コード順に表示では完全に五十音順に変更できなくて困っています。エクセルでリストをPHNETIC関数で五十音にソートできたのですが、この順番をデータローダ等で一括で順番変更できないでしょうか。

私の回答としてはメタデータをワークベンチを使って一括更新するとしましたが、さらに調べてみると他にもVisual Studio Code + Salesforce CLIも使えるかもしれません。

+ [Visual Studio Code + Salesforce CLIを使用したメタデータのリリース](https://base.terrasky.co.jp/articles/cHjOB)

# Tooling APIを使う方法もありそうです。

+ [Update Salesforce Picklist Values and Labels](https://success.jitterbit.com/cloud-studio/cloud-studio-reference/connectors/salesforce/salesforce-how-tos/update-salesforce-picklist-values-and-labels/)
+ [Tooling API を活用するための検討](https://qiita.com/Keiji_otsubo/items/25b82bbd250da9a486e3)

### ステップ 1: 選択リストのメタデータと値を取得する

最初のステップは、DurableId選択リストフィールドのを取得することです。この使用例では、Salesforce Query アクティビティEntityDefinitionを使用して、次のサブクエリを使用してオブジェクトをクエリします

テスト用に作ったCustomObjectを指定して実行してみます。カスタムオブジェクトなので__cを忘れずに... 私は忘れてしまって表示されずにしばし悩みました。

:::note
SELECT (SELECT Id, DeveloperName, DurableId, QualifiedApiName, Label, DataType FROM Fields WHERE DataType = 'Picklist'), DeveloperName, QualifiedApiName, NewUrl FROM EntityDefinition WHERE QualifiedApiName = 'CustomObject__c'
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/9b93a080-95d5-0893-52ba-97dfed54eb5e.png)

:::note
[{"Id":"000000000000000AAA","DeveloperName":"myPicklist","DurableId":"01I5i0000034UoY.00N5i00000UNAbr","QualifiedApiName":"myPicklist__c","Label":"myPicklist","DataType":"Picklist"}]
:::

以下のFieldDefinitionの説明みたいですが、どのように更新されるか理解できないですね。 HTTP PATCHで上書きする？

+ [CustomField](https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/tooling_api_objects_customfield.htm)
+ [FieldDefinition](https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/tooling_api_objects_fielddefinition.htm#topic-title)


# とりあえず、Postmanでtooling APIを使ってこの項目を表示させる

参考にした記事

https://salesforce.stackexchange.com/questions/162390/how-to-update-picklist-values-along-with-record-types-using-metadataservice

ToolingAPIはコレクションにあるのですが、CustomFieldがないんですよね。タブを追加して作ってしまいましょう。（使い方がよく分かりませんが...）

パラメータのCustomFieldIdをこのページだけで指定したいのですが追加できませんでした。仕方ないので変数にします。

```
{{_endpoint}}/services/data/v{{version}}/tooling/sobjects/CustomField/{{CustomFieldId}}
```

こんな感じで...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/3064226a-7f07-0891-3f9a-db6ce10c0924.png)

実行すると、以下のようにこのカスタム項目の情報を取得できましたね。
ここまで簡単にできた...(ちょっと嘘です1時間悩みました）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/5f4baa61-4304-1ef2-5495-dea6b4346003.png)

変数を:CustomFieldIdのように書き換えたら、このページだけの変数になりましたね。

```
{{_endpoint}}/services/data/v{{version}}/tooling/sobjects/CustomField/:CustomFieldId
```

ちゃんと値もセットできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/91ce73fc-7ac0-b3e5-3f2f-66e4ce8afaee.png)


### メッソドのPATCHを作って送信してみる

先程得たJsonをコピーして、ラベルをA1,B1,C1に変えてみます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/4819f006-4601-7c2f-ddfb-78613622bde2.png)

それでは送信します。

400のエラー？ 不正なリクエスト？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/48a0706f-c004-ba3d-3712-1442e9326bfa.png)

この例を見るとBodyにJsonをセットしてPATCHとして送信しているんだけど...

https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/intro_rest_resource_examples.htm

To update a Tooling API object by ID, for example, MetadataContainer:

```
req.setEndpoint('https://MyDomainName.my.salesforce.com/services/data/v59.0/tooling/sobjects/
MetadataContainer/ + containerID + '/');
req.setBody('{"Name":"NewlyNamedContainer"}');
req.setMethod('PATCH');
```

Bodyのフォーマットが違うかと思って、先の記事で見たように以下の部分を削除します。
使わない感じですね。

```
    "attributes": {
        "type": "CustomField",
        "url": "/services/data/v59.0/tooling/sobjects/CustomField/00N5i00000UNAbrEAH"
    },
    "Id": "00N5i00000UNAbrEAH",
    "TableEnumOrId": "01I5i0000034UoYEAU",
    "DeveloperName": "myPicklist",
    "Description": null,
    "Length": null,
    "Precision": null,
    "Scale": null,
    "RelationshipLabel": null,
    "SummaryOperation": null,
    "InlineHelpText": null,
    "MaskType": null,
    "MaskChar": null,
    "NamespacePrefix": null,
    "ManageableState": "unmanaged",
    "CreatedDate": "2023-12-04T01:49:46.000+0000",
    "CreatedById": "0055i00000BXxguAAD",
    "LastModifiedDate": "2023-12-04T06:37:17.000+0000",
    "LastModifiedById": "0055i00000BXxguAAD",
    "EntityDefinitionId": "01I5i0000034UoY",
```


### エラーの詳細が分からない

メイン画面のいろんなところをクリックしていると... あったエラーの詳細があったよ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/3f63e592-6106-d73a-dc82-6a35dae10685.png)

```
[
    {
        "message": "Cannot deserialize instance of complexvalue from VALUE_NULL value null or request may be missing a required field",
        "errorCode": "JSON_PARSER_ERROR"
    }
]
```
意味が分からん。

complexvalue のインスタンスを VALUE_NULL 値 null から逆シリアル化できないか、リクエストに必須フィールドが欠落している可能性があります


そういえば、最初に読んだ記事では意味不明で読み飛ばしたけど"valueSettings": null'を'"valueSettings": []に置き換えていそうです。

As a transformation will not generate an empty array, a script is used to replace the null value returned in the valueSettings field with an empty array:


```
$io = Replace($io,'"valueSettings": null','"valueSettings": []');
```

この部分かな？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/ee5c9bee-7f7c-0917-7778-b4b63647929d.png)

違うエラーになりましたね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/a0a9a53f-2533-407d-a429-cdfffcf1ef32.png)

リターンする内容はないということかな？

サイド取得したら、見事にラベルが変更できてました。
Apexでコードを書くよりかなり楽ですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/c774e28e-c160-753f-7ea3-1ee52255dbf1.png)

オブジェクトマネージャーからも確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/e5bc3e77-d600-0f01-0adf-57115deec87d.png)


# 重要なこと　今定義されている全ての選択値を再度更新しないと、非アクティブ化されてしまう。

+ [Updation to Global Picklist Value Set through Tooling API makes the existing values deactivated state in salesforce](https://salesforce.stackexchange.com/questions/400001/updation-to-global-picklist-value-set-through-tooling-api-makes-the-existing-val)

:::note
This is the standard behavior with picklists. When you perform a deployment against the picklist, the value set is updated to match the deployed picklist values, and any values existing in the org that are not present in the deployment are deactivated.

There is no way to change this behavior or to address individual picklist value set entries.

Instead, you must retrieve the picklist value set first, modify it to add the entries you desire, and then deploy the entire value set back into the org.

これは選択リストの標準的な動作です。選択リストに対してリリースを実行すると、値セットはデプロイされた選択リストの値と一致するように更新され、組織内に存在し、リリースに存在しない値はすべて非アクティブ化されます。

この動作を変更したり、個別の選択リスト値セットのエントリに対処したりする方法はありません。

代わりに、最初に選択リスト値セットを取得し、それを変更し
:::

# 値も変えてみる

既にA1(API名はA)のレコードがある状態でAPI名をA2に変更してみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/7f8380f7-95c7-4f70-a3c1-1d60ee821101.png)

以下のエラーになります。

```
[
    {
        "message": "Duplicate label: A1",
        "errorCode": "FIELD_INTEGRITY_EXCEPTION",
        "fields": []
    }
]
```

+ [グローバル選択リスト値セットを使用したリリースのエラー「ラベルの重複」](https://help.salesforce.com/s/articleView?id=000390855&type=1)

その選択リスト値の API 参照名に変更があるグローバル選択リスト値セットを含む変更セットをリリースしようとすると、「ラベルの重複」エラーが発生する場合があります。

これは、期待される動作とみなしてください。

変更セットを介して選択リスト値の変更をリリースすると、システムは選択リスト値の API 参照名をその一意識別子として参照します。そのため、選択リスト値のラベルのみを変更しようとした場合、システムはその API 参照名に基づいて値を認識し、変更を行います。

ただし、API 参照名自体を変更しようとした場合、システムはその意図を、新しい選択リスト値を作成しようとしたものと判断し、同じラベルを持つ値がシステムにすでに存在していることを認識し、結果としてラベル重複エラーをスローします。

ということは、API名は変更できないってこと？

まだ使ているレコードが無いAPI名BをB1に変えるけど、API名は変更できませんね。ラベルだけかな？


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/fabf9328-95cb-4057-85f6-14f1721c059b.png)



# 役に立ちそうな資料

+ [Update picklist value and add it in record type using apex](https://ayubansarii.wordpress.com/2019/11/29/update-picklist-value-and-add-it-in-record-type-using-apex/)
+ [Update Record Type Picklist Selected Value Using REST API](https://www.reddit.com/r/salesforce/comments/17bz4io/update_record_type_picklist_selected_value_using/)
+ [Updating picklist values through tooling API not performing same validations as UI](https://issues.salesforce.com/issue/a028c00000gAw31AAC/updating-picklist-values-through-tooling-api-not-performing-same-validations-as-ui)