Salesforce ユーザーをAPI経由で作成する

## 概要
本記事では、Pythonを使ってSalesforceユーザーを手動作成ではなく、API経由で作成する方法を記載します。めんどくさい手作業のステップを最小化し、効率化を図ることが目的です。

## 背景
現在、私は自社開発企業にてSalesforceシステムの運用を担当していますが、毎月発生するユーザー作成依頼に手を焼いていました。手動で画面上からユーザーをポチポチ作成していると、どうしても時間がかかってしまい、何よりも気が重くなってしまいます。
そこで、「ユーザー情報をスプレッドシートなどに入力してもらい、それをCSVファイルに変換 → スクリプトからAPI経由で自動作成」というフローを構築すれば効率的ではないかと思い立ち、スクリプトを開発することに至りました。

## 前提
言語はPythonを使用していますが、ほかの言語でも同様のアプローチは可能です（APIをコールできるなら何でもOKです）。
Salesforce ユーザー作成に必要なAPIの認証情報（ユーザー名、パスワード、セキュリティトークンなど）を取得済みであることが前提です。
## ユースケース
使い方としては、ユーザー作成が必要になったタイミングで、このスクリプトをターミナルから実行して、ユーザーをまとめて作成するイメージを想定しています。実際のディレクトリ構成例は下記の通りです。
流れの詳細は、下記に記載しますがとりあえずソースコード見ながら確認したいという方は、リポジトリのURLを参考までに貼っておきます。スクリプトの実行方法などは、リポジトリのREADME.mdに記載してあります。
https://github.com/Kyohei-takiyama/create-sf-user

```bash
コードをコピーする
src/
├── __init__.py                 # Pythonパッケージとして認識させるための空ファイル
├── envs/                       # .envファイルを環境ごとに配置するフォルダ
├── files/
│   └── ユーザー作成シート.csv  # ユーザー作成用のデータを管理したCSVファイル
├── functions/
│   ├── __init__.py             # functionsパッケージの初期化
│   └── create_users.py         # CSV読み込み→Salesforceユーザー作成の処理をまとめたモジュール
├── main.py                     # エントリポイント。プロジェクト全体を統括して実行するスクリプト
├── settings.py                 # 環境変数やアプリ設定を管理するモジュール
└── utils/
    ├── __init__.py             # utilsパッケージの初期化
    └── salesforce_api_client.py # Salesforce REST API呼び出し用クライアントクラスをまとめたモジュール
```
ユーザー作成時には「files」内のCSVを参照しながら「functions」配下のスクリプトを実行する流れを想定しています。

## 開発する必要があるもの
1. Salesforce と連携するためのクライアントツール
まずはSalesforce APIに接続する必要があるため、Pythonの場合はsimple_salesforce というライブラリが便利です。
 [simple_salesforce](https://github.com/simple-salesforce/simple-salesforce)には様々な認証方式がありますが、今回はお手軽なSalesforceのユーザー名・パスワード・セキュリティトークンを使って認証し、そのままREST APIや各種オブジェクト操作を簡単に呼び出せます。

    ```python
    Salesforce(
        username=settings.SF_USER,
        password=settings.SF_PASSWORD,
        security_token=settings.SF_TOKEN,
        domain=settings.SF_DOMAIN,
    )
    ```

2. CSVを読み込む処理
続いてはユーザー情報を格納したCSVファイルを読み込む処理です。Python標準のcsvモジュールや、pandasなどを使って読み込むことが多いですが、今回は軽量化のために標準ライブラリのcsvを使う方法がシンプルかと思います。
1行ずつUser情報（例: FirstName, LastName, Email, Username, ProfileIdなど）を取得し、そのままSalesforceへ投げる形です。

    ```python
    コードをコピーする
    import csv
    
    def create_users_from_csv(csv_path):
        with open(csv_path, mode='r', encoding='utf-8') as f:
            reader = csv.DictReader(f)
            for row in reader:
                # row["Email"] や row["FirstName"] などを取得
                # Salesforce APIに対してユーザー作成処理を呼ぶ
                ...
    ```            
3. Salesforce のREST API仕様を確認する
ユーザー作成にあたっては、SalesforceのREST API (Userオブジェクト) を利用します。

APIのエンドポイントは、/services/data/vXX.X/sobjects/User となります。（バージョンは組織によって異なるので適宜合わせてください）
リクエストボディで必要になるフィールドは、主に以下の通りです。
FirstName, LastName, Email, Username, Alias, TimeZoneSidKey, LocaleSidKey, EmailEncodingKey, LanguageLocaleKey, ProfileId etc.
プロファイルIDを指定すると、そこに紐づいたライセンスが割り当てられるという仕組みです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/e1b885ee-db98-51ed-da7a-78d8b6004bda.png)

ここで、手動で画面から操作する場合と大きく異なる点はありませんが、**ProfileId**の値を用意しておかないとエラーになるケースが多いです。
事前にSalesforceのSetupで「割り当てたいプロフィールID」を取得しておき、そのIDをCSVや設定ファイルなどに記載しておくとスムーズでしょう。

## 今回意識したところ

- .envファイルなどにある環境変数をコマンド実行時に切り替えてSandboxでの実行や本番環境での実行を出し分けるようにすること
- 本番環境実行時には、コマンド内のプロンプトで一回確認する処理を入れて、誤った実行を避けるようにすること(下記のようなプロンプトを表示する処理をコード内に記述しています)
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/f4acff18-9209-34f3-2b44-cec7d7936ca5.png)
    ```python
    import os
    import sys
    from settings import Settings
    
    from functions.create_users import create_users_from_csv
    
    def main():
        settings = Settings()
        env_name = settings.Config.env
    
        print(f"実行環境: {env_name}")
    
        # もし本番実行の場合に確認プロンプトを出す
        if env_name == "prod":
            confirm = input("⚠️ 本番環境で実行します。よろしいですか？ (yes/no): ")
            if confirm.lower() not in ("yes", "y"):
                print("====== 処理中断 ====== ")
                sys.exit(1)
    
        # ここから処理を実行
        print("====== 処理開始 ======")
    
        create_users_from_csv("src/files/ユーザー作成シート.csv")
    if __name__ == "__main__":
        main()
    ```

## 最後に
以上のように、毎回手動でユーザーを作成していると時間と手間がかかる作業を、スクリプトに置き換えることで大幅に効率化することができます。
スプレッドシートなどでユーザー情報を先方に入力してもらい、その情報をCSVに変換してスクリプトを回すだけで、数十人、数百人といったユーザーが一度に作成されるのはとても快適です。
環境変数や認証情報などの管理にも少々気を遣う必要がありますが、セキュリティを十分に確保しながら運用できれば、業務の無駄を大幅に省く手段となるはずです。

もし同様の課題でお困りの場合は、ぜひ本記事を参考にAPI経由でのユーザー作成にチャレンジしてみてください。