【kintone】async/await を使って他のアプリからデータを取得する

こんにちは！

今回はJavaScriptのasync/awaitという小技を使って、
他のアプリのデータを取得してみたいと思います！

ふんわりと初心者向けに書きましたので、ふんわりと読んでもらえたら嬉しいです✨✨

# アプリの準備

フォームには「数値」フィールドを1つだけおいたアプリを4つ作ります。
アプリA～Cのレコード番号1のレコードの数値を全部足した値を
アプリA+B+Cの数値フィールドに自動的に表示させます。

|アプリA|アプリB|
|:-:|:-:|:-:|:-:|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/339b8834-11df-1925-214e-c512e68719b0.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/cff1f9ba-145d-a952-8687-46eb23930ec7.png)|
|**アプリC**|**アプリA+B+C**|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/d3f5c486-d70a-46cc-edb9-c7c0b2d39ee5.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/8df42221-070b-99c2-6f85-a98757b99959.png)|

# JavaScriptを書く

## 他のアプリのデータを取ってくるプログラムの書き方

JavaScriptは「アプリA+B+C」用に書きます。

他のアプリのレコード番号が1のレコードを取ってくるには、下記リンク先を参考にすると

参考：
[kintone REST API リクエスト](https://developer.cybozu.io/hc/ja/articles/202166310)
[レコードの取得（GET）](https://developer.cybozu.io/hc/ja/articles/202331474#step1)

```js
const resp = kintone.api('/k/v1/record', 'GET', {'app': アプリのID,'id':1});
```

のように書けます。（アプリのIDには、アプリA~CのIDが入ります）

↑のように書いた場合、respの中にrecordの情報が入っていて、

```js
record = resp.record // 取ってきたレコードの情報
fieldData = resp.record.フィールドコード.value //取ってきたレコードの、指定フィールドの値
```

のように、欲しい値を取得することができます。

以上を踏まえると、
下記のようなプログラムで、
アプリA～Cの「数値」を全部足すことができるような気がします。

```js
(()=>{

    kintone.events.on('app.record.create.show',  event => {

        //アプリA～Cからレコード番号1のレコードの情報を取ってくる
        const respA =  kintone.api('/k/v1/record', 'GET', {'app': アプリAのID,'id':1});
        const respB =  kintone.api('/k/v1/record', 'GET', {'app': アプリBのID,'id':1});
        const respC =  kintone.api('/k/v1/record', 'GET', {'app': アプリCのID,'id':1});

        // アプリA～Cのレコード番号1の数値フィールドの合計を、アプリA+B+Cの数値フィールドに入れる
        event.record.数値.value = Number(respA.record.数値.value) 
                                + Number(respB.record.数値.value) 
                                + Number(respC.record.数値.value);
        return event;
        
    });    

})();

```

しかしこれではうまくいきません。


### コンソールに表示されるエラー

先程のJavaScriptを実際に動かしてみると、コンソールには下記のようなエラーが表示されます。
※コンソールはWindowsPCでchromeを使用している場合、Ctrl+Shift+iのショートカットキーで表示されるウィンドウ内の「console」タブをクリックして表示できます。
参考：[コンソールの開き方](https://www.javadrive.jp/javascript/console/index1.html#:~:text=%E3%81%8B%E3%82%89%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B-,%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%82%92%E8%A1%A8%E7%A4%BA,Chrome%20%E3%82%92%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%BE%E3%81%99%E3%80%82&text=%E7%94%BB%E9%9D%A2%E4%B8%8B%E9%83%A8%E3%81%AB%E3%83%87%E3%83%99%E3%83%AD%E3%83%83%E3%83%91%E3%83%BC%E3%83%84%E3%83%BC%E3%83%AB,%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%82%82%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82)

```console
Uncaught TypeError: Cannot read property '数値' of undefined
```

'数値'というプロパティがないよ！と言われています。

`respA.record.数値.value`の部分でエラーが発生していて、
**レコード情報に数値フィールドの情報がないので足し算できないよ**という意味です。

でも下記のように、レコードの情報を取ってくるプログラムを書いていました。
なぜ数値フィールドの値が取れないのでしょうか。

```js
        //アプリA～Cからレコードの情報を取ってくる
        const respA =  kintone.api('/k/v1/record', 'GET', {'app': アプリAのID,'id':1});
        const respB =  kintone.api('/k/v1/record', 'GET', {'app': アプリBのID,'id':1});
        const respC =  kintone.api('/k/v1/record', 'GET', {'app': アプリCのID,'id':1});

```



### 2人でやり取りをするプログラム！？

先程のプログラムですが、
kintone.api(～)という命令により、kintone REST APIが他のアプリのレコードの情報を取りに行っている間に、JavaScriptのプログラムが進もうとしてエラーになっています。

一見、JavaScriptがただ上から順番に実行されて終わるプログラムのように見えて、
JavaScriptさんとkintone REST APIさんという二人がやり取りをしながら処理をするようなプログラムになっています。

チャットツール風に表すとこんな感じになります。

JavaScriptの気持ちになってお読みください↓

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/f04e77af-8fc0-9eea-b582-6ecc922bde27.png" width=400px>

JavaScriptさんは、まだレコードの内容がわからないというのに値を足そうとして失敗します。
JavaScriptとAPI、二人のタイミングが合っていません。

こういった、**タイミングを合わせる必要のある処理を「非同期処理」**といいます。


ではプログラムの方を見てみましょう。
この行では、JavaScriptがAPIに「アプリAのレコード取ってきてー」とお願いしただけで安心してしまって、
APIからのレスポンスを待たずにJavaScriptのプログラムが先に進んでしまうという現象が起こっています。

```js
//アプリAのレコード取ってきてー！のプログラム
const restA = kintone.api('/k/v1/record', 'GET', {'app': アプリAのID,'id':1});
```

アプリAからレコードを取得完了する前に、
プログラムの方は進んでしまって、↓の計算式を先に解こうとします。

```js
//よし、計算するぞ！（respA,respB,respCがなにか分かっていない）
event.record.数値.value = Number(respA.record.数値.value) 
                        + Number(respB.record.数値.value) 
                        + Number(respC.record.数値.value);
```

まだrespA、respB、respCが分からない状態なのに、
respA.record.数値.valueという値を使おうとした結果、先程のエラーが出ます（＞＜）


## ではどうすればよいのか？

これはタイミングを合わせて、以下のチャットのようになると良さそうです。

またまたJavaScriptさんの気持ちになって読んでください↓

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/97b7a6d4-4777-5490-cec5-9c846f233ec5.png" width=400px>

APIが他のアプリのレコードの情報を取ってくるまで（レスポンスがあるまで）JavaScriptは待っています。

## async/awaitを書き加える

APIが「情報を取ってくるのを待つ」ために
async/awaitという非同期処理のレスポンスを待ってくれる仕組みを使ってみましょう。


async は「今からタイミング合わせるよ～！」
await は「返事（レスポンス）が帰ってくるの、待つ！」

の意味です。使い方は簡単。

**asyncを、同期したい関数の前（今回は` event => {`の前）に
awaitを、待ちたい非同期処理の前（`kintone.api`の前）に置くだけです。**


```js
(()=>{
    //awaitを使いたい関数の前（event =>の前） に asyncを書く
    kintone.events.on('app.record.create.show', async event => {
        //await をつけると、非同期処理のレスポンスを（kintone.apiの処理）を待ってくれる
        const respA = await kintone.api('/k/v1/record', 'GET', {'app': 197,'id':1});
        const respB = await kintone.api('/k/v1/record', 'GET', {'app': 198,'id':1});
        const respC = await kintone.api('/k/v1/record', 'GET', {'app': 199,'id':1});

        event.record.数値.value = Number(respA.record.数値.value) 
                                + Number(respB.record.数値.value) 
                                + Number(respC.record.数値.value);
        return event;
    });    
})();
```

これで他のアプリのデータを取ってきてフィールドに表示することができるようになります。

試してみてね！


# まとめ

`kintone.api(~~)`は非同期処理となるので、タイミングを合わせる（同期をとる）ように工夫してプログラムを書かなくてはいけません。

また、await中で待ち続けている間は、プログラムがずーっと止まったままになってしまうので、kintoneの画面がフリーズした状態になります。ですので、使い所も考えながらawaitしましょう＾０＾

そんな、kintoneカスタマイズの肝となりそうな「非同期処理」ですが
非同期処理についてふんわりと理解してもらい、次につなげてもらえたら嬉しいなと思います＾＾

developer networkの↓も参考に挑戦してみてくださいね！
[async/awaitの使い方](https://developer.cybozu.io/hc/ja/articles/900001244323-%E7%9B%AE%E6%8C%87%E3%81%9B-JavaScript%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA%E4%B8%AD%E7%B4%9A%E8%80%85-%EF%BC%92-Promise%E3%81%AE%E3%81%8B%E3%82%8F%E3%82%8A%E3%81%ABasync-await%E7%B7%A8-#usage)