empApi で Streaming API を使ったレコードの変更監視

今回は、empApi を使ったレコードの監視方法のご紹介です。

## empApi って？
Lightning コンポーネントから、Salesforce ストリーミング API を利用するための機能です。
基本的には [CommetD](https://cometd.org/) を内包した pub/sub 方式で、 Streaming API に接続して指定のチャネルを購読(Subscribe)します。


##購読できるチャネルの種類
lightning:empApi では Salesforce が提供する４つのチャネルを購読出来ますが、それぞれ仕様が違うので要件にあったものを選ぶのが大切です。

| チャネル種別        | 利用シーン              |
|------------------|-----------------------|
|プッシュトピック       |特定のレコードの変更を監視    |
|汎用ストリーミング     |特定のユーザーへのイベント通知|
|変更データキャプチャ  |他システムとのデータ同期      |
|プラットフォームイベント |上記以外                  |

##利用方法
利用法は、Aura と LWC で異なります。

- Aura
    - lightning:empApi サービスコンポーネントのコンポーネントメソッドを呼び出して使う
- LWC 
    - lightning/empApi モジュールから関数をインポートして使う


##準備
####プッシュトピックの作成
今回は取引先のレコード更新を試すので、プッシュトピックを作成します。

```java:トピックの追加
PushTopic topic = new PushTopic();
topic.Name = 'AccountChangeEvent';
topic.Query = 'SELECT Id, Name FROM Account';
topic.ApiVersion = 45.0;
topic.IsActive = true;
insert topic;
    
```

## サンプルコード
#### Aura の場合

```html:SampleEmpApi.cmp
<aura:component implements="flexipage:availableForAllPageTypes" access="global" >
    <!-- Private Attributes -->
     <aura:attribute access="private" type="String"  name="result"   />
    
    <!-- Streaming Service -->
    <lightning:empApi aura:id="empApi"/>
    
    <!-- User Interface -->
    <lightning:button variant="brand" label="Start Subscribe" onclick="{!c.onButtonClicked}"/>
    <lightning:textarea value="{!v.result}" label="Result" />
</aura:component>
```


```js:SampleEmpApiController.js
({
    onButtonClicked : function(c, e, h) {
        
        const empApi = c.find('empApi');
        empApi.isEmpEnabled() // EMP Connector が利用可能か確認する
        .then($A.getCallback(function(isEmpEnabled) {
            
            if (isEmpEnabled) { // EMP Connector が利用可能
                
                // Streaming API との接続でエラーが発生した時のコールバックを登録
                empApi.onError($A.getCallback(function(error) {
                    console.error('EMP API error: ', error);
                }));
                
                // Channel に対し購読を開始
                const channel = '/topic/AccountChangeEvent'; // プッシュトピックの場合
                //const channel = '/data/AccountChangeEvent'; // 変更データキャプチャの場合
                const replayId = -1;
                empApi.subscribe(channel, replayId, $A.getCallback(function(event) {
                    const data = event.data;
                    console.log(JSON.stringify(data, null, 2));
                    c.set('v.result', JSON.stringify(data, null, 2));
                }));
                console.log('start');
                
            } else { // EMP Connector が利用不可
                console.error('EMP API error: ', 'EMP Connector is not supported');
            }
        }))        
    },
})
```

#### LWC の場合
```xml:myEmpApi.js-meta.xml
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="myEmpApi">
    <apiVersion>46.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>
```

```html:myEmpApi.html
<template>
    <lightning-button variant="brand" label="Start Subscribe" onclick={onButtonClicked}></lightning-button>
    <lightning-textarea label="Result" value={result}></lightning-textarea>
</template>
```


```js:myEmpApi.js
import { LightningElement, track } from "lwc";
import { subscribe, isEmpEnabled } from "lightning/empApi";

export default class MyEmpApi extends LightningElement {
  @track result;

  onButtonClicked() {

    // EMP Connector が利用可能か確認する
    isEmpEnabled().then(isEnabled => {

      // EMP Connector が利用可能
      if (isEnabled) {
        const channel = "/topic/AccountChangeEvent"; // プッシュトピックの場合
        //const channel = '/data/AccountChangeEvent'; // 変更データキャプチャの場合
        const replayId = -1;

        // Channel に対し購読を開始
        subscribe(channel, replayId, data => {
          this.result = JSON.stringify(data, null, 2);
        });
      } else {
        // EMP Connector が利用不可
        console.error("EMP API error: ", "EMP Connector is not supported");
      }
    });
  }
}
```

####3.確認結果
`Start Subsribe` ボタンを押してから、取引先を変更すると result にイベント通知の内容が表示されます。
sobject の中にプッシュトピックでクエリした項目が入っていますね。
![Screen Shot 2019-02-19 at 17.30.52.png](https://qiita-image-store.s3.amazonaws.com/0/26378/ed7a2d85-60f5-72f3-47f6-bf7503fe8085.png)


ちなみに変更データキャプチャなど、チャネル種別によって通知内容が違うので気をつけましょう。
![Screen Shot 2019-02-19 at 17.32.32.png](https://qiita-image-store.s3.amazonaws.com/0/26378/2f57bcd2-4c85-5b69-f524-d1237fec0938.png)

## 参考
- [Lightning Web Component - Emp API](https://developer.salesforce.com/docs/component-library/bundle/lightning-emp-api)
- [Aura Component - Emp API](https://developer.salesforce.com/docs/component-library/bundle/lightning:empApi/documentation)