Zoom APIをDjangoで扱ってみる
Zoom APIを利用して部屋の作成とかする案件がありそうなので勉強のために調べてみたことメモ。
Django
なのはこれも勉強のため。。
前提
- Django: 2.2.x
ゴール
手順
1. Zoomにてアプリ登録を行う
- OAuth - Build an App - Documentationにアクセス
- 右上「Create App」をクリック
- Zoomアカウントでのログインを求められるのでログインする
- 「Choose your app type」にて「OAuth > Create」をクリック
- 「Create on OAuth app」というモーダルが表示されるので必要に応じて情報を入力する
- App Name: 任意(今回はSamplaApp)
- Choose app type: 任意(今回はAccount-level appを選択)
- Would you like to publish this app on Zoom App Marketplace?: Offを選択
- モーダル内「Create」をクリックするとアプリが作成され、以下情報が取得できる
- 取得できる情報
- Client ID
- Client Secret
- またOAuthでの認証後にリダイレクトされるページのURLを指定する(今回は
http://localhost:8000/zoom/auth/complete
とする) - Whitelist URLも登録しておく(今回は
http://localhost:8000
)
- 取得できる情報
- 画面左側メニュー「Scopes」をクリック
- 「Add scopes+」をクリック
- 必要に応じて認証のスコープを設定する(今回はMeetingを作成できればよいので
user:read:admin
,meeting:write:admin
,meeting:write
を選択)- APIのリファレンス(API Reference)に必要なスコープが書かれているので参考にする
- スコープの選択が完了したらモーダル内「Done」をクリック
- 必要に応じて認証のスコープを設定する(今回はMeetingを作成できればよいので
2. Djangoで実装を行う
2-1. デモアプリを作成する
アプリ名はわかりやすくzoom
とする
$ python manage.py startapp zoom
settings.py
にてzoom
を有効化する
# <project-root>/<project-app>/settings.py INSTALLED_APPS = [ ..., # My Applications 'zoom.apps.ZoomConfig', ]
2-1. 認証, アクセストークンの取得
認証に関するルーティングを設定する
# <project-root>/<zoom/urls.py from django.urls import path from . import views urlpatterns = [ # /auth: 認証ページにリダイレクト # /auth/complete: 認証完了 # /meeting: ミーティング一覧 # /meeting/add: ミーティング作成 path('', views.index, name='zoom_index'), path('auth/', views.auth, name='zoom_auth'), path('auth/complete', views.index, name='zoom_auth_complete'), ] # <project-root>/<project-app>/urls.py ... urlpattenrs = [ ..., path('zoom/', include('zoom.urls')), ..., ]
ルーティングに対応するTemplate
, View
を作成する
とりあえず必要な箇所以外は一旦処理を省略する
<!-- <project-root>/zoom/templates/auth/auth.html --> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Zoom - Auth</title> </head> <body> <h1>Zoom Auth</h1> <a href="{{ auth_href }}">Zoomで認証する</a> </body> </html> <!-- <project-root>/zoom/templates/auth/complete.html --> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Authentication complete</title> </head> <body> Zoom Authentication Complete </body> </html>
# <project-root>/zoom/views.py import requests, base64, json from django.shortcuts import render, redirect from django.urls import reverse # Create your views here. def auth(request): '''認証ページへリダイレクトさせる''' client_id = 'SnSyF4YFQOGpJlXXTbIE4w' client_secret = 'ofqwMjnKuuQba4tmmTQVOlfgmj447uHw' if 'code' not in request.GET: print('get code') auth_url = 'https://zoom.us/oauth/authorize' response_type = 'code' # ngrokでlocalhostをSSL形式でアクセスできるようにする redirect_uri = 'https://XXXXXX.ngrok.io/zoom/auth' auth_href = auth_url + '?response_type=' + response_type + '&client_id=' + client_id + '&redirect_uri=' + redirect_uri return render(request, 'auth/auth.html', { 'auth_href': auth_href }) else: print('get token') auth_url = 'https://zoom.us/oauth/token' code = request.GET.get('code') grant_type = 'authorization_code' redirect_uri = 'https://XXXXXX.ngrok.io/zoom/auth' # basic認証用のコードを作成(client_ID:Client_Secretをbase64エンコード) client_basic = base64.b64encode('{0}:{1}'.format(client_id, client_secret).encode()) # POST用のパラメータとカスタムヘッダを作成する post_payload = { 'code': code, 'grant_type': grant_type, 'redirect_uri': redirect_uri } post_header = { 'Authorization': 'Basic {0}'.format(client_basic.decode()) } # # Exec POST response = requests.post(auth_url, data=post_payload, headers=post_header) response_text = json.loads(response.text) if 'access_token' in response_text: # 認証結果をセッションに保存 request.session['zoom_access_token'] = response_text['access_token'] request.session['zoom_token_type'] = response_text['token_type'] request.session['zoom_refresh_token'] = response_text['refresh_token'] request.session['zoom_expires_in'] = response_text['expires_in'] request.session['zoom_scope'] = response_text['scope'] return redirect('zoom_auth_complete') else: return render(request, 'auth/auth.html', { 'auth_href': 'hoge' }) def auth_complete(request): '''認証完了ページ''' pass
ビルトインサーバを起動し、https://XXXXXX.ngrok.io/zoom/auth/
にアクセスする
リンクをクリックするとZoomのOAuth画面が表示される
※ Zoom APIを利用する場合はhttps
が必須らしくlocalhost
を利用する場合はngrok
などのサービスを使ってhttps
環境を作成する必要がある
OAuthを許可したら再度https://XXXXXX.ngrok.io/zoom/auth/
にリダイレクトされればOk
この時、URLパラメータにcode=XXXXXXXXXXX
というものがついている。これはアクセストークンの取得に必要となる
取得したコードをもとにアクセストークンを取得する
アクセストークンの取得にはZoomにアプリ登録した際のClientID
,Client_Secret
を使いBasic認証経由でPOST
する必要がある
Basic認証状はCientID:Client__Secret
をbase64エンコード
して送信する
またPOST
の際に設定するredirect_uri
パラメータだが、ここはZoomのアプリ登録時に設定したRedirect URL for OAuth
の文字列を設定していたがそれではエラー(redirect uri mismatch
)が出る
どうやらPOST
するページのURLでないとダメらしいので注意
# basic認証用のコードを作成(client_ID:Client_Secretをbase64エンコード) client_basic = base64.b64encode('{0}:{1}'.format(client_id, client_secret).encode()) # POST用のパラメータとカスタムヘッダを作成する post_payload = { 'code': code, 'grant_type': grant_type, 'redirect_uri': redirect_uri } post_header = { # base64エンコードした状態だとbyte形式となるので.decode()でString形式に変換する 'Authorization': 'Basic {0}'.format(client_basic.decode()) }
アクセストークンが取得できたらセッションに情報を追加して完了ページへリダイレクトする
簡略化のためにセッションにしているが本来はcookie
あたりがいいと思われる
2-2. 部屋の作成(時間の変更)
アクセストークンが取得できたら試しにミーティング部屋を作ってみる
Views
を以下の通り編集する
# <project-root>/zoom/views.py def auth_complete(request): '''認証完了ページ''' get_user_url = 'https://api.zoom.us/v2/users' access_token = request.session['zoom_access_token'] # ユーザー情報の取得 get_user_headers = { 'Authorization': 'Bearer {0}'.format(access_token) } get_user_response = requests.get(get_user_url, headers=get_user_headers) get_user_response_text = json.loads(get_user_response.text) user_info = get_user_response_text['users'][0] # 部屋の作成 create_meeting_url = 'https://api.zoom.us/v2/users/{0}/meetings'.format(user_info['id']) create_meeting_params = { 'topic': 'Sample Meeting', 'type': 2, # scheduled meeting 'start_time': '2020-11-02 T 12:00:00', 'duration': 180, 'timezone': user_info['timezone'], } create_meeting_params_json = json.dumps(create_meeting_params).encode('utf-8') create_meeting_headers = { 'Authorization': 'Bearer {0}'.format(access_token), 'Content-Type': 'application/json' } create_meeting_response = requests.post(create_meeting_url, data=create_meeting_params_json.decode(), headers=create_meeting_headers) create_meeting_response_text = json.loads(create_meeting_response.text) return render(request, 'auth/complete.html')
ミーティング部屋を作成するためにはユーザーID
が必要となるため、API経由で取得する
APIの詳細はList Users - Users - Zoom API - API Referenceを参照
アクセストークンはAuthrization: Bearer XXXX
というヘッダをつけて送信する
# ユーザー情報の取得 get_user_headers = { 'Authorization': 'Bearer {0}'.format(access_token) } get_user_response = requests.get(get_user_url, headers=get_user_headers) get_user_response_text = json.loads(get_user_response.text) user_info = get_user_response_text['users'][0]
ユーザーID
が取得できたらミーティング部屋を作成する
基本的に「ミーティング名称」「ミーティングタイプ」「開始日」「ミーティング時間」「タイムゾーン」あたりを設定していればよい
他にも様々なパラメータを渡すことができるので詳細は Create a Meeting - Meetings - Zoom API - API Reference を参照
この時、パラメータはdict
ではなくjson
を利用して渡すことになるため、ヘッダに「Content-Type: application/json
」が必要となる(ない場合は300 - Unsupported Content Type
というエラーが返ってくる)
# 部屋の作成 create_meeting_url = 'https://api.zoom.us/v2/users/{0}/meetings'.format(user_info['id']) create_meeting_params = { 'topic': 'Sample Meeting', 'type': 2, # scheduled meeting 'start_time': '2020-11-02 T 12:00:00', 'duration': 180, 'timezone': user_info['timezone'], } create_meeting_params_json = json.dumps(create_meeting_params).encode('utf-8') create_meeting_headers = { 'Authorization': 'Bearer {0}'.format(access_token), 'Content-Type': 'application/json' } create_meeting_response = requests.post(create_meeting_url, data=create_meeting_params_json.decode(), headers=create_meeting_headers) create_meeting_response_text = json.loads(create_meeting_response.text)
リクエストが正常に完了したらZoomを立ち上げ、スケジュールに追加されていれば処理完了