【ZOOM API】フレームワークで会議作成アプリを作ってみた(Node.js体験)

## はじめに
こちらは、「Qiita Engineer Festa 2022」の参加記事です！

https://qiita.com/official-campaigns/engineer-festa/2022


自分自身、APIを使用したwebアプリを作ったことが無く、
何か作って動かしてみたいと思っていたところ、こちらのzoomキャンペーンで
テーマ「Zoom APIを実装してみた」を発見。

初の記事投稿も、勉強のためにやってみようと思い書いてみました。

## 作ったもの
ボタンを押すと即時ミーティングが表示されます。
押すたびに書き換わります。
![zoom_meeting-Google-Chrome-2022-07-02-17-36-36_Trim.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725328/e2de3943-0201-82b4-d05d-c981e9f7c2c3.gif)


## 実装方法について
zoomの参考ページにNodeでのコード例があったので、Node.jsでの実装に挑戦。
できるだけ短時間で動かすために、フレームワークとテンプレートエンジン(Express, ejs)を使ってみました。

https://qiita.com/yosuke-sawamura/items/d8ec07ac8b7b0335a22b

:::note warn
javaScriptが全く得意ではない自分が、勉強用に作成したものです。
Node.js、Expressも今回が初見のため、
不自然なコーディング等あると思います。ご了承ください。

作成するアプリは、動作体験用のため実用には向きません。
:::



## 環境、使用したツール
- Windows10
- Node.js : 18.4.0
- npm : 8.12.1
- VSCode

## 作成手順
#### 動作環境の準備
開発環境とテンプレートエンジンをインストールします。

node.jsがインストールされていない場合は、
[こちらから](https://nodejs.org/en/download/) インストールします。

作業フォルダを準備し、
以下、１つずつ順番に実行します。
```
// フレームワーク、テンプレートエンジンのインストール
npm install express-generator -g
express --view=ejs アプリ名

// パッケージの追加インストール
cd アプリ名/
npm install
npm install jsonwebtoken
npm install request-promise
```

これだけで、開発準備ができました。とても便利です。

#### jwtの発行
API呼び出しにトークンが必要なので、以下を参考に発行します。
発行したら、メモ帳などに控えておきます。

https://qiita.com/yosuke-sawamura/items/d8ec07ac8b7b0335a22b

:::note info
jwt.ioから取得したトークンではうまくいかなかったので、
手順６の画面で、「View JWT Token」をクリックして取得しました。
:::


#### userIdの取得
下記ページの手順通りに実行すると、userinfoが取得できました。

https://github.com/zoom/zoom-api-jwt


成功すると、「User's infomation」が表示されるので、
「id : ***」の値を、メモしておきます。

##  コードを追加する
「動作環境の準備」で用意したフォルダに、以下を追記します。

####  config.jsを追加する
userIdの取得で使用した「config.js」をコピーし、
/routesの中に追加します。

```config.js
const env = 'production'

//insert your API Key & Secret for each environment, keep this file local and never push it to a public repo for security purposes.
const config = {
	production:{	
		APIKey : 'APIキーを入力',
		APISecret : 'APISecretを入力',
		UserId : 'UserIdを入力',  // 追加する
		token : 'JwtTokenを入力'} // 追加する
};
module.exports = config[env]
```



#### 画面を変更する
views/index.ejs　の、\<body>部分に以下を追加します。
会議発行ボタン、会議URL等を表示するコードを追記します。

```index.ejs
    <form action="/" method="post">
      <p>zoom_meeting_creat!</p>
      <input type="submit" name="create" value="会議作成"/>
    </form>

    <ul>
      <% for (var i = 0; i < meeting.length; i++) { %>
      <li><span><a href="javascript:void(0);" onclick="window.open('<%= meeting[i] %>','_blank')">会議を開始する！ </a></span></li>
      <span>ミーティングid : <%= id[i] %></span><br>
      <span>パスワード : <%= pass[i] %></span><br>
      <% } %>
    </ul>
<%
if(meeting.length > 0){
  meeting.length = 0;
  id.length = 0;
  pass.length = 0;
}    
%>

```


#### API呼び出しを実装
routes/index.js　を以下に書き換えします。

:::note warn
jwt.signで取得したトークンではアクセスできなかったため、とりあえず手動でトークンを貼り付けしています。（payloadの値を要調整？）
そのため、90分ごとにconfig.jsの値を更新しないと動きません。
マーケットプレイスと同じトークンが発行できるよう要調整です…。
:::

:::note warn
発行済の会議IDを無効にするなど、細かい点は考慮していません。
:::

``` index.js
const express = require('express');
const router = express.Router();

// API取得用
const jwt = require('jsonwebtoken');
const config = require('./config');
const rp = require('request-promise');

// 画面表示用
let meeting = [];
let id = [];
let pass = [];

// トークンの取得
//Use the ApiKey and APISecret from config.js
// const payload = {
//   iss: config.APIKey,
//   exp: ((new Date()).getTime() + 5000)
// };
// const token = jwt.sign(payload, config.APISecret);
// console.log(token);

//tokenが一致しないので、サイトから直接記載
const token = config.token;

// GETリクエスト時の動作
router.get('/', function(req, res, next) {
  res.render('index', { 
    title: 'zoom_meeting',
    meeting: meeting, id: id, pass: pass
   });
});

// POSTリクエスト時の動作
router.post('/', function (req, res, next) {
  var options = {
    // API呼び出し
    method: "POST",
    uri: 'https://api.zoom.us/v2/users/' + config.UserId + '/meetings',
    json: true, //Parse the JSON string in the response
    headers: {
      authorization: 'Bearer ' + token ,
        'User-Agent': 'Zoom-api-Jwt-Request',
        'content-type': 'application/json'
      },
    body: {
        'topic': 'test meeting',
        'type': '1',
        'timezone': 'Asia/Tokyo',
        'settings': { 'use_pmi': 'false' }
    }
}

rp(options)
   .then(function (resJson) {
       var result = JSON.stringify(resJson, null, 2)
       meeting.push(resJson.start_url);
       id.push(resJson.id);
       pass.push(resJson.encrypted_password);
       res.redirect('/');
   })
   .catch(function (err) {
       console.log(err);
   })
  });

module.exports = router;
```


## 動作確認
以下のコマンドを実行します。
```
npm start
```

[localhost:3000]を開きます
http://localhost:3000/

起動できました！
![localhost3000.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725328/871cb4c4-3d37-3e13-f2c9-f26ffb76c954.jpeg)

会議作成ボタンを押すと、冒頭の「作ったもの」と同じ動作が確認できました。

:::note info
ボタンを押しても画面遷移しない場合は、トークンの時間切れが予想されます。
jwtの発行手順で、再度取得してconfig.jsに貼り付けしてください。

（「ctrl + c」で停止後、「npm start」で再起動します。）
:::


## 感想
- 恥ずかしながら、JavaScriptをほとんど使ったことがなく、この程度のものでも
かなり試行錯誤の末、やっと動くものが完成しました。
（普段は、javaを使用した業務システムがメインなのです...）
API呼び出しだけでなく、javaScriptの練習にもなりました。


- 「手順を記事にまとめる」という作業も思いのほか時間がかかりましたが、
記事にすることで曖昧な部分が無くなり、より理解ができました。

- 今回一つAPIを実装出来たので、ここから色んなAPIを実装すれば、どんどん作りこめそうです。自分専用で、カスタマイズして動かしてみたいと思いました。