# Engoo API
**Version: 0.0.5**
**2021/09/09**
認証
===
全てのAPIは[OAuth 2.0](https://openid-foundation-japan.github.io/rfc6749.ja.html)の認証が必要となります。Client Credentialsのフローでトークンの発行を取得できます。トークンには有効期限があるため、有効期限が切れたトークンのエラー処理が全てのAPIに必須となります。
### 例
```bash
$ curl -s -u <uid>:<secret> -X POST https://api.engoo.com/api/oauth/token -F grant_type=client_credentials
```
```json
{
"access_token": "eyJhbGciOiJIUzI1N...",
"token_type": "Bearer",
"expires_in": 2629746,
"created_at": 1589772238
}
```
注記:上記のコードではOAuth 2.0のclient credentialsをBasic認証として指定しています。
## トークンの有効期限切れ扱い
有効期限が切れたトークンでMeeting APIをアクセスすると以下の通りのエラーが出てきます。
```bash
curl -X POST https://api.engoo.com/api/meeting_bookings \
-s -H 'Authorization: Bearer <token>' -H "Content-Type: application/json" --data \
'{ "data": { "_new": true, "_type": "MeetingBooking", "_version": 4, "brand": { "_ref": "ref1" },
"open": true }, "references": { "ref1": { "_type": "BrandReference", "_version": 1,
"id": "b14db7e2-e751-11ea-9b41-ef30aae3c3e6" } }, "versions": { "BrandReference": 1,
"MeetingBooking": 4, "Rtc.Participant": 3, "Rtc.Room": 2, "Text": 1,
"TextTranslation": 1, "UserProfile": 1 } }'
```
```json
{
"error": {
"_type": "Error",
"_version": 1,
"status": 401,
"detail": "Presented OAuth2 token was not valid.",
"title": null,
"code": "Auth.TokenInvalid",
"meta": {},
}
}
```
トークンの有効期限切れはOAuth 2.0の流れの通常の処理となっているので、以上の`Auth.TokenInvalid`のエラーの処理はトークンの更新のために必須となります。
API概要
===
各APIレスポンスは以下の形式です。
```json
{
"data": {
"_new": true,
"_type": "SomeType",
"_version": 4,
"id": "c14db7e2-e751–11ea–9b41-ef30aae3c4a0",
"something": {
"_ref": "ref1"
},
"references": {
"ref1": {
"_type": "AnotherType",
"_version": 1,
"id": "b14db7e2-e751-11ea-9b41-ef30aae3c3e6"
}
},
"versions": {
"AnotherType": 1,
"SomeType": 4
}
}
}
```
### データ
`data`の項目にオブジェクトのデータが入っています。`_`(アンダーバー)から始まる特別な項目が三つあります。
**`_new`** `boolean`
オブジェクトが本リクエストで作成された状態。
**`_type`** `string`
オブジェクトのタイプ。
**`_version`** `integer`
オブジェクトのバージョン。
### 関連項目
`references`の項目に、関連オブジェクトの情報が入っています。本オブジェクトには、`"ref1"`のような文字列で指定されるので、参照する際、キーとして`references`でアクセスできます。
### バージョン情報
`versions`の項目に、各オブジェクトのバージョンが入っています。
各エンティティにバージョンを指定できます。たとえ`versions`で指定されているバージョンより上のバージョンがリリースされても、前のバージョンのレスポンスが返ってきます。バージョンの対応が終了する可能性もありますので、常にアップデートをお願いいたします。`versions`を設定し、都合のいい時にアップデートをしてください。
### フィルター
一部のGETリクエストには、クエリパラメータで指定するフィルターがあります。例えば、指定のメールアドレスのユーザーのみ取得する際、ユーザーのインデックスAPIのURLに`email=taro@example.com`のクエリパラメータを追加すると該当のメールアドレスのあるユーザーのみが返ってきます。
オブジェクト
===
User
---
**`abilities`** `array(string)`
ユーザーの権利。一般のユーザーの場合は空
**`birthdate`** `isodate`
生年月日
**`brand`** `Brand`
ユーザーが付属する`Brand`
**`confirmed`** `boolean`
メールアドレス認証済みの状態
**`deleted_at`** `isodate`
削除された日付。ユーザーが削除されていない場合は値が`null`
**`display_name`** `string`
ユーザーの表示名。講師にも表示されるため、英数のみ
**`email`** `string`
ログインするとき、又は通知が届くメールアドレス
**`gender`** `string`
ユーザーの性別
**`has_password`** `boolean`
パスワード有無の状態
**`id`** `uuid`
ユーザーID
**`image`** `Image`
プロフィール画像。現在、表示されない
**`language`** `IEFTBCP47`
UIやコンテンツが表示される言語
**`last_authenticated_at`** `isodate`
最終ログイン日
**`marketing_email_consent `** `boolean`
マーケティングメールの許可状態
**`name`** `string`
ユーザーの名前。メールや他の連絡用のため、言語問わず自由に設定できる
**`password_type`** `string: {"user", "staff"}`
パスワード強化制限種類。管理者の場合、値が`"staff"`となり、パスワードの最低長が長くなる
**`profile_completed`** `boolean`
ユーザーのプロフィール入力が完了した状態。未完了の場合、ログインする際、プロフィール編集画面が出てくる
**`staff_member`** `StaffMember`
管理者である場合の関連情報
**`student_tos_agreement `** `boolean`
利用規約に承諾した状態。許諾していない場合、ログインする際、承諾画面が出てくる
**`teacher`** `Teacher`
講師である場合の関連情報
**`timezone`** `isotimezone`
ユーザーの時間帯
**`unconfirmed_email`** `string`
ユーザーがメールアドレスを変更しようとする際、確認済みでないメールアドレス
Teacher
---
**`id`** `uuid`
講師ID
**`name`** `string`
講師の名前。
**`gender`** `string`
講師の性別。
**`nationality`** `string`
講師の国籍。
**`enabled`** `boolean`
講師の外部
Lesson Booking
---
**`id`** `uuid`
講師ID
**`name`** `string`
講師の名前。
**`gender`** `string`
講師の性別。
**`nationality`** `string`
講師の国籍。
**`enabled`** `boolean`
講師の外部
## API
Users
---
**URI:** `https://api.engoo.com/api/users`
**ヘッダー:**
Content-Type: `application/json`
Authorization: `Bearer <token>`
### GET
`https://api.engoo.com/api/users`
ユーザーリストを取得する。
**メソッド:** GET
**返答タイプ**: `array(User)`
**対応フィルター**: `brand`, `email`, `confirmed`
### GET
`https://api.engoo.com/api/users/:uuid`
`:uuid`で指定するユーザーを取得する。
**メソッド:** GET
**返答タイプ**: `User`
### POST
`https://api.engoo.com/api/users`
**メソッド:** POST
**返答タイプ**: `User`
**リクエストボディ:**
```json
{
"data": {
"_new": true,
"_type": "User",
"_version": 19,
"brand": {
"_ref": "ref1"
},
"display_name": "Taro",
"email": "taro@example.com",
"language": "ja",
"marketing_email_consent": true,
"name": "太郎",
"profile_completed", true,
"student_tos_agreement": true,
"timezone": "Asia/Tokyo"
},
"references": {
"ref1": {
"_type": "BrandReference",
"_version": 1,
"id": "b14db7e2-e751-11ea-9b41-ef30aae3c3e6"
}
},
"versions": {
"BrandReference": 1,
"User": 4,
}
}
```
### 例
```bash
curl -X POST https://api.engoo.com/api/users \
-s -H 'Authorization: Bearer <token>' -H "Content-Type: application/json" --data \
'{ "data": { "_new": true, "_type": "User", "_version": 19, "brand": { "_ref": "ref1" },
"display_name": "Taro", "email": "taro@example.com", "language": "ja", "marketing_email_content": true, "name": "太郎", "profile_completed": true, "student_tos_agreement": true, "timezone": "Asia/Tokyo" }, "references": { "ref1": { "_type": "BrandReference", "_version": 1,
"id": "b14db7e2-e751-11ea-9b41-ef30aae3c3e6" } }, "versions": { "BrandReference": 1,
"User": 19} }'
```
Lesson Booking
---
**URI:** `https://api.engoo.com/api/lesson_bookings`
**メソッド:** POST
**ヘッダー:**
Content-Type: `application/json`
Authorization: `Bearer <token>`
**リクエストボディ:**
```json
{
"data": {
"_new": true,
"_type": "MeetingBooking",
"_version": 4,
"brand": {
"_ref": "ref1"
},
"open": true
},
"references": {
"ref1": {
"_type": "BrandReference",
"_version": 1,
"id": "b14db7e2-e751-11ea-9b41-ef30aae3c3e6"
}
},
"versions": {
"BrandReference": 1,
"MeetingBooking": 4,
"Rtc.Participant": 3,
"Rtc.Room": 2,
"Text": 1,
"TextTranslation": 1,
"UserProfile": 1
}
}
```
### 例
```bash
curl -X POST https://api.engoo.com/api/meeting_bookings \
-s -H 'Authorization: Bearer <token>' -H "Content-Type: application/json" --data \
'{ "data": { "_new": true, "_type": "MeetingBooking", "_version": 4, "brand": { "_ref": "ref1" },
"open": true }, "references": { "ref1": { "_type": "BrandReference", "_version": 1,
"id": "b14db7e2-e751-11ea-9b41-ef30aae3c3e6" } }, "versions": { "BrandReference": 1,
"MeetingBooking": 4, "Rtc.Participant": 3, "Rtc.Room": 2, "Text": 1,
"TextTranslation": 1, "UserProfile": 1 } }'
```
```json
{
"data": {
"id": "b238a024-6775-11eb-a6b0-9bc2d3886842",
"_type": "MeetingBooking",
"_version": 4,
"creator": {
"_ref": "ref:h:4D4OfKSc6mdMXJicKct82E8a+LCqrIIluldka5/Eq7I="
},
"rtc_room": {
"id": "b2393b1a-6775-11eb-a6b1-332be4c69a28",
"_type": "Rtc.Room",
"_version": 2,
"rtc_participants": []
},
"brand": {
"_ref": "ref:h:N0Uft7z8+Do9TSPugumec8z9IOeVQ2vyoUMjikhVHS0="
},
"open": true,
"created_at": "2021-02-05T05:47:56Z"
},
"references": {
"ref:h:4D4OfKSc6mdMXJicKct82E8a+LCqrIIluldka5/Eq7I=": {
"id": "e9f693a5-e601-571d-8bc8-fe400943c7e4",
"_type": "UserProfile",
"_version": 1,
"display_name": "Taro"
},
"ref:h:N0Uft7z8+Do9TSPugumec8z9IOeVQ2vyoUMjikhVHS0=": {
"id": "b14db7e2-e751-11ea-9b41-ef30aae3c3e6",
"_type": "BrandReference",
"_version": 1,
"name": {
"id": "a2722016-f226-44b7-82cd-f0d01d0683b8",
"_type": "Text",
"_version": 1,
"text": "Bubo Bubo Academy",
"formatted": false,
"lock_version": 0,
"text_translations": []
}
}
},
"meta": {
"supplementary": {
"b228a024-6775-11eb-a6b0-9bc2d3886842": {
"host_key": "gGj-o713srUybzohf2PQmg"
}
}
}
}
```
レッスンリンクの生成
===
**URLベース:** `https://engoo.com/app/meeting/#{id}`
一般用のリンクは上記のURLベースにMeeting APIで取得する`data`の`id`項目で作成することができます。
ミーティングのhost用URLも存在します。host用のリンクでアクセスするとレッスンコンテンツで回答情報が表示されます。
Meeting APIで取得する`host_key`の項目でhost用リンクを生成できます。
`https://engoo.com/app/meeting/{id}?hostKey={host_key}`
## 短縮したリンク形式 (任意)
ミーティングのUUIDをエンコードすることで見やすい短縮したリンク生成も可能です。
### 例
**Ruby:**
```ruby
Base64.urlsafe_encode64([uuid.tr('-','')].pack("H*"), padding: false)
```
**PHP:**
```php
preg_match_all('/[0-9a-fA-F]{2}/', preg_replace('/-/', '', $guid), $characterBuckets);
if ($characterBuckets === null) {
throw new Error("Cannot convert to a base64 encoded guid string: ${guid}.");
}
$characters = '';
foreach ($characterBuckets[0] as $key => $value) {
$characters .= chr(intval($value, 16));
}
$str = base64_encode($characters);
$str = str_replace('+', '-', $str);
$str = str_replace('/', '_', $str);
$str = str_replace('=', '', $str);
return $str;
```
**結果**
`https://engoo.com/app/meeting/rkccSxTWQ9uwyI4Ta9BE0Q`