LoginSignup
9

More than 5 years have passed since last update.

AWS Lambda から Salesforce のカスタムオブジェクトにレコードを追加する

Last updated at Posted at 2017-08-02

はじめに

社内のとある取り組みにおいて、AWS の Lambda から Salesforce のカスタムオブジェクトにデータを入れる仕組みが必要になったので、その仕組みを実装するための覚え書きです。

本稿では、Node.js、AWS、Salesforce を使用するので、前提としてこの辺りの知識が必要になります。
が、筆者は上記の知識ゼロだったので、なくてもなんとかなる。はず。(すばらしい記事を残してくれている方々に感謝

手順

  1. 作業環境・用意するもの
  2. Node.js で Salesforce へ接続
  3. AWS の準備
  4. Lambda関数の作成
  5. Lambda から Salesforce に接続
  6. Salesforce カスタムオブジェクトにレコードを追加する

作業環境・用意するもの

【作業環境】

  • Windows7、Node.js 7.1.0(本稿作業時)

【用意するもの】

  • AWS と Salesforce アカウント
  • AWS S3、IAMロール、ポリシーなどの設定
  • データを入れるための Salesfoce オブジェクト
  • Salesforce 接続アプリケーション

Node.js で Salesforce へ接続

こちらの記事が大変参考に。
OAuth2 JWT Bearer Token フローを使ってSalesforceへアクセスする

必要に応じてモジュールをインストールする。上記の記事では下記のモジュールを使用する。

  • fs
  • jsonwebtoken
  • request
  • jsforce

AWS の準備

前準備として今回使用する IAM ロール、ポリシー、S3 バケットなどの作成、設定をしておく。

Lambda 関数の作成

AWS で Lambda 関数を作成する。
本稿では下記設定で作成した。

  • 「Lambda」ページの 「Lambda 関数の作成」をクリックすると設計図の選択画面に遷移する。
  • フィルターに「S3」と入れ、「s3-get-object」を選択。
  • 「バケット」項目は 3 で作成したバケットを選択
  • 「イベントタイプ」は「put」を選択
  • プレフィックス、サフィックスは空欄で OK
  • 「トリガーの有効化」にチェックを入れて「次へ」

LambdaでS3にデータを格納する

関数の設定

関数の名前と、必要に応じて説明を入力。ランタイムは Node.js。

Lambda 関数のコード

とりあえずデフォルトのままで OK。

Lambda 関数ハンドラおよびロール

  • ハンドラ:デフォルト( index.handler )で OK。
  • ロール:「既存のロールを選択」で 3 で作成したロールを選択

ここまで入力して関数を作成する。

作成した関数をテストして動作を確認

  • 事前に S3 になんかファイルを入れておく
  • 「アクション」から「テストイベントの設定」を選択
  • サンプルイベントテンプレートから「S3 Put」を選択。
  • サンプルコード 14 行目辺りにある「"key": "HappyFace.jpg"」の値を先ほど入れておいたファイル名に
  • サンプルコード 19 行目辺りにある「"name": "sourcebucket"」の値を準備したバケット名に変更
  • 「保存してテスト」をクリックしてテスト。

Lambda から salesforce に接続

手順4で作成したLambda関数のコードをコピーし、手順2で作成したJSファイルと合体させる。
Lambda や Salesforce 接続に必要なモジュールなどは最初に読み込んでおいてOK。

index.js

const...
const...

exports.handler = (event, context, callback) => {
 // 2 で作成の salesforce に接続するプログラムをここにぶち込む
};

とするだけ。
これで S3 にファイルがアップロードされた時、2 で作成した salesforce 接続処理が走る。
ここで合体した JS ファイル(仮に index.js)を関数パッケージとして Lambda にアップロードする。

  • index.js
  • pemファイル
  • node_module

これらをまとめて ZIP にする。
Lambda 関数画面のコードタブ、コード エントリ タイプから「ZIP ファイルをアップロード」を選び、
作成した ZIP ファイルをアップロードする。

(pem ファイルもまとめてここでアップロードするため、JS 内で呼び出す PEM ファイルのパスに注意)
ZIP をアップロードしたら「テスト」をクリックし、ログを確認して 2 の動作ログが出ていれば OK。

Salesforce カスタムオブジェクトにレコードを追加する

Salesforce にカスタムオブジェクトを作成し、手順2で作成したコードの

index.js

conn.query('SELECT Id, Name FROM Account LIMIT 5').then(function(qr) {
 console.log('Done:', qr.done);
 console.log('Fetched Records:', qr.records);
});

の部分を

index.js

conn.sobject(" オブジェクト名 ").create({
 " 項目名 ": 追加する値
});

とすることでカスタムオブジェクトにレコードを追加することができる。

最後に、ここまでの内容を元に、S3に保存した画像を Amazon Rekognition(DetectFaces)に送り、
解析結果を Salesforce のオブジェクトに保存する実装例をメモしておく。

index.js

'use strict';
const aws = require('aws-sdk');
const fs = require('fs');
const s3 = new aws.S3({apiVersion: '2006-03-01'});
const jwt = require('jsonwebtoken');
const request = require('request');
const jsforce = require('jsforce');
const rekognition = new aws.Rekognition();
const TOKEN_ENDPOINT_URL = 'https://login.salesforce.com/services/oauth2/token';
const ISSUER = '********'; // Salesforce 接続アプリのコンシューマ鍵(client_id)
const AUDIENCE = 'https://login.salesforce.com'; // 固定
const cert = fs.readFileSync('./key/myapp.pem'); // 秘密鍵の読み込み
exports.handler = (event, context, callback) =>{

    const bucket = event.Records[0].s3.bucket.name;
    const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
    const params = {
        Bucket: bucket,
        Key: key,
    };

    // rekognition に送るデータ
    const rekogParams = {
        Image: {
            S3Object: {
                Bucket: bucket,
                Name: key
            }
        },
        Attributes: ["ALL"]
    };

    rekognition.detectFaces(rekogParams, function (err, data) {
        if (err) {
            console.log(err, err.stack); // an error occurred
        } else {

            // JWTに記載されるメッセージの内容
            const claim = {
                iss: ISSUER,
                aud: AUDIENCE,
                sub: '**********', // 接続するSalesforceのユーザアカウント名
                exp: String(Date.now() + 3 * 60 * 1000) //現在時刻から3分間のみ有効
            };

            // JWTの生成と署名
            var token = jwt.sign(claim, cert, {algorithm: 'RS256'});

            // JWT Bearer Token フローによるアクセストークンのリクエスト
            request({
                method: 'POST',
                url: TOKEN_ENDPOINT_URL,
                form: {
                    grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
                    assertion: token
                }
            }, function (err, response, body) {
                if (err) {
                    return console.error(err);
                }
                var ret = JSON.parse(body);
                console.log(ret)
                var conn = new jsforce.Connection({
                    accessToken: ret.access_token,
                    instanceUrl: ret.instance_url
                });

                // Salesforce オブジェクト「rekognitionData」に Rekognition の解析結果を追加
                for (var i in data.FaceDetails) {
                    conn.sobject("rekognitionData__c").create({
                        "AgeRangeLow__c": data.FaceDetails[i].AgeRange.Low,
                        "AgeRangeHigh__c": data.FaceDetails[i].AgeRange.High,
                        "Gender__c": data.FaceDetails[i].Gender.Value,
                        "Smile__c": data.FaceDetails[i].Smile.Value,
                        "Eyeglasses__c": data.FaceDetails[i].Eyeglasses.Value,
                        "Sunglasses__c": data.FaceDetails[i].Sunglasses.Value,
                        "Beard__c": data.FaceDetails[i].Beard.Value,
                        "Mustache__c": data.FaceDetails[i].Mustache.Value,
                        "EyesOpen__c": data.FaceDetails[i].EyesOpen.Value,
                        "Emotions1__c": data.FaceDetails[i].Emotions[0].Type,
                        "Emotions2__c": data.FaceDetails[i].Emotions[1].Type,
                        "Emotions3__c": data.FaceDetails[i].Emotions[2].Type,
                    }, function (err, ret) {
                        if (err || !ret.success) {
                            return console.error(err, ret);
                        }
                    });
                }
            });
            callback(null, data.FaceDetails);
        }
    });
}
;

上記コードとオブジェクトの項目が少し違いますが、こんな感じでレコードが追加されます。

sfobj.jpg

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9