Cisco Webex Teams API(旧Cisco Spark API)の基本とREST API

> 2018.05.22. Cisco Webex TeamsからCisco Webex Teamsへの名称変更に伴い、記載内容を変更しました。

## この記事では、以下に関して記載しています
* Cisco Webex Teams APIやSDKの基本事項
* Cisco Webex Teams APIやSDKの機能概要
* REST APIの一般的な話
* Cisco Webex TeamsのREST APIに関する概要

## 以下の記事程度の内容が前提の知識になります
* [Cisco Webex Teams(旧Cisco Spark)とつながるアプリの開発の始め方](https://qiita.com/thrzn41/items/2454506a405f9606530c)
* [Cisco Webex Teams(旧Cisco Spark)の開発者サイトの使い方](https://qiita.com/thrzn41/items/a1a2660d03ba34400fd5)
* [Cisco Webex Teams(旧Cisco Spark)のBot用アカウントの作り方](https://qiita.com/thrzn41/items/672870bb8a6ab2ca44b2)


# 1. Cisco Webex Teams APIとSDK

Cisco Webex Teamsは、開発者向けにシンプルなAPIを提供しています。
また、音声通話やビデオ通話機能を含むSDKを提供しています。

開発者向けのほぼすべての情報は、
[Cisco Webexの開発者サイト](https://developer.webex.com/) ([https://developer.webex.com/](https://developer.webex.com/))から入手できます。

## 1.1. Cisco Webex Teams API

本記事執筆時点(2018年02月時点)では、
Cisco Webex Teams APIというと、
主には、Cisco Webex Teamsのメッセージングの機能を中心に扱うRESTベースのWeb APIがメインになります。

後の章では、主に、Cisco Webex TeamsのREST APIの概要を記載します。

また、Cisco Webex TeamsのAPIを扱いやすくしたSDKもいくつか提供されています。
SDKを使うと、Cisco Webex TeamsのREST APIで提供されている機能以外にも、
音声通話やビデオ通話の機能も利用できます。

Cisco Webex Teamsとつながるアプリの開発を始める場合は、
**SDKに踏み込むよりも前に**、
**まずは、REST APIからはじめるのがおススメ**です！

SDKは環境を選ぶため、苦労するケースもあるかもしれません。
REST APIは、環境にほぼ依存しないので、始める段階で苦労する可能性は低いと言えます。

## 1.2. Cisco Webex Teams SDK

**Beta版も含めて**、本記事執筆時点(2018年01月31日時点)で、
主に以下のSDKが提供されています。

* iOS向けのSDK(音声通話、ビデオ通話機能あり)
* Android向けのSDK(音声通話、ビデオ通話機能あり)
* Webブラウザ向けのSDKとウィジェット(音声通話、ビデオ通話機能あり)
* Node.js向けSDK
* Java向けSDK

**※ 音声通話やビデオ通話機能、ウィジェットを利用する際は、
必ず、OAuth2を利用して取得したトークンを利用してください。**
**※ 開発者トークンを利用したものが例示されている場合もありますが、
運用上、開発者トークンは使わないようにします。**

**※ SDKに関しては、本記事では、詳細には触れません。**

# 2. REST API

まずは、**Cisco Webex Teams関係なく**、一般的なREST APIの話です。
Cisco Webex TeamsのREST APIの話は、第3章からになります。

世の中的な、REST APIの多くは、
"REST"というアーキテクチャの思想を多く取り入れた、
WebベースのAPIを指す場合が多いと思います。

"REST"自体は、"**RE**presentational **S**tate **T**ransfer"の略らしいですが、
あまり細かいことを言い出してもキリがないので、
まずは、とりあえず、なんとなくを理解していくことを目標にします。

## 2.1. REST APIのポイント

ここでは、**厳密さはさておき**、"REST API"を、

> "REST"というアーキテクチャの思想を多く取り入れた、WebベースのAPIである

と、捉えることにします。

その場合、ポイントは以下のような感じになると思います。

* クライアント(APIを呼び出す側)とサーバでリソースをやりとりする
* HTTP(普通はHTTPS)を使ってリソースのやりとりをする
* 各リソースには、一意なURIでアクセスする
* リソースの**新規作成**、**取得**、**更新**、**削除**が主な操作である

> 「リソース」とは、ここでは、「小さな情報の塊」程度の理解でよいと思います。
> 例えば、『「名前」と「電話番号」と「メールアドレス」を１つずつまとめた塊』を
> １つの『連絡先という「リソース」』と捉えるイメージです。
> REST APIを提供する側では、リソースの構造も定義されているはずです。

### 2.1.1. HTTP(普通はHTTPS)を使ってリソースのやりとりをする

リソースのやりとりには、HTTPを使うのが一般的です。
HTTPで定義されている各種機能を使えば、うまくリソースをやりとりすることができます。

例えば、以下のようなことがポイントになります。

* HTTPのURIでリソースを特定できる。
* HTTPのメソッド(POST, GET, PUT, DELETEなど)を使ったリソースに対する操作を指定できる。
* HTTPのヘッダを使って、サーバに処理やリソースに関するヒントを与えたり、サーバからヒントをもらったりできる。
* HTTPのボディ(本文)を使ってリソースの中身を受信したり送信したりできる。
* HTTPのレスポンスのステータスコードを使って、操作が成功したかどうかの判断ができる。

やりとりする情報にはセンシティブな情報が含まれる場合が多いので、
多くのREST APIでは、通常、
TLSを利用したセキュアなHTTPSが必須になっているはずです。

世の中のほとんどのプログラミング言語では、
HTTPSを使った通信のためのライブラリなり、フレームワークなり、機能なりが
提供されているので、
大抵のプログラミングを言語を利用して、HTTPSの通信は実現可能なはずです。

HTTPSを利用する場合は、セキュアなコネクション(TLSを利用)の開始時に、
サーバ側の証明書の検証等を行いますが、
通常は、各プログラミング言語向けのライブラリ等の内部で、
検証の処理等はやってくれます。
この検証処理等をわざわざ無効化するようなサンプルコードをたまーに見かけますが、
**このような破滅的な実装は、絶対にマネしないようにしましょう**。

### 2.1.2. 各リソースには、一意なURIでアクセスする

各リソースには、一意なURIを利用してアクセスします。

たとえば、以下のようなURIです。

`https://apiserver.example.com/path/to/resource/id0001`

各リソースをどのようなURIで表現するかは、各REST APIの設計にもよりますが、
よくあるパターンは以下のような感じです。

* `https://{APIサーバのアドレス}/{APIのバージョン}/{リソースの種類}/{リソースのID}`
* `https://{APIサーバのアドレス}/{APIのバージョン}/{リソースの種類}`

| 項目     | 概要     | 例 |
| :------------- | :------------- | :------------- |
| {APIサーバのアドレス} | REST APIを提供しているサーバ。このサーバを介してリソースをやりとりする。 | api.example.com |
| {APIのバージョン} | 互換性のために、パスにバージョンを含む場合が多い。 | v1 |
| {リソースの種類} | 各リソースのカテゴリのようなもの。 | messages |
| {リソースのID} | 各リソースのID。{リソースの種類}配下のリソースで重複することはない。 | id0123765 |


例えば、こんな感じになります。

* `https://api.example.com/v1/messages/id0123765`
* `https://api.example.com/v1/messages`

{リソースの種類}、{リソースのID}の部分は、
さらに、サブカテゴリを含む場合や、リソースの構造的な都合で、
ネストするREST APIも存在します。
例えば、こんな感じです。
`https://api.example.com/v1/contacts/cid0123765/friends/fid4560123`
この辺りは、データの設計上の都合や、APIの設計によるものですが、
ネストはあまりない方が、シンプルになる場合が多いので、API利用者側には嬉しいはず。

また、
`https://example.com/api/v1/messages`などのように、パス中に`/api`を含むケースも
比較的によく見かけます。

大まかには、

* URIが{リソースのID}で終わっている場合
* URIが{リソースの種類}で終わっている場合

の2パターンに分類できると思います。

#### 2.1.2.1 URIが{リソースのID}で終わっている場合

`https://{APIサーバのアドレス}/{APIのバージョン}/{リソースの種類}/{リソースのID}`
のような形式です。
(例: `https://api.example.com/v1/messages/id0123765`)

**既に存在している**、**特定のリソース**を指し示すURIになります。
ある時点で、このURIは、**特定のリソースを一意に指し示します**。
同じ瞬間に、**まったく同じURIが、異なるリソースを指し示すことはありません**。

この形式のURIの場合は、一般的には、
**特定のリソースの取得(GET)**、**特定のリソースの更新(PUT)**、**特定のリソースの削除(DELETE)**の操作が可能です。
(カッコ内は対応するHTTPのメソッド名です。)

#### 2.1.2.2 URIが{リソースの種類}で終わっている場合

`https://{APIサーバのアドレス}/{APIのバージョン}/{リソースの種類}`
のような形式です。
(例: `https://api.example.com/v1/messages`)

**まだ存在していないリソース**や、**ある種類のリソース全体**などを指し示すURIになります。
{リソースのID}がないため、**特定のリソースを指し示すのではなく**、
**リソースの種別**や**リソース全体**などのような、やや抽象的なものを指し示します。

この形式のURIの場合は、一般的には、
**ある種類のリソースを新規に作成(POST)**、**ある種類のリソースの一覧取得(GET)**、**ある種類のリソースの全体を削除(DELETE)**の操作が可能です。
(カッコ内は対応するHTTPのメソッド名です。)

ある種類のリソースの一括更新(PUT)も設計は可能だと思いますが、
この機能は提供されていない場合が多いと思います。

ある種類のリソースの一覧取得(GET)、ある種類のリソースの全体を削除(DELETE)では、
対象を限定するために、URIのクエリパラメータも利用されることが多いと思います。
(例: `https://api.example.com/v1/messages?year=2017&month=12`)

### 2.1.3 リソースの新規作成、取得、更新、削除が主な操作である

これまで記載してきたURIの話と、HTTPメソッドで指定する操作を組み合わせると、
リソースに対する大抵の操作は実現できることになります。
まとめるとこんな感じです。

| HTTPメソッド | URIが{リソースのID}で終わっている | URIが{リソースの種類}で終わっている |
| :------------- | :------------- | :------------- |
| POST    | 通常は提供されない | 新規リソースの作成 |
| GET     | 特定のリソースの取得 | リソース全体の一覧取得 |
| PUT     | 特定のリソースの更新 | 通常は提供されない |
| DELETE  | 特定のリソースの削除 | リソース全体の一括削除 |

"通常は提供されない"の部分は、無理に設計できないわけではないと思いますが、
普通は、扱いづらいものに仕上がるのではないかと思います。

(他が安全というわけではありませんが、)
"リソース全体の一括削除"は、かなり危険な処理である場合が多いので、
この機能は提供していないREST APIも多いと思います。

### 2.1.4 HTTPの本文(ボディ)に関して

リソースをやりとりするのには、HTTPの本文(ボディ)が利用されます。
最近では、JSON形式でやり取りするケースが多いと思います。

中身はさておき、JSONでは、こんな感じで、キー名と値やオブジェクトのペアで、
構造化されたデータのやりとりが可能です。

``` json
{
  "name" : "俺様",
  "email" : "oremasa@example.com"
}
```

構造は、REST API提供側であらかじめ定義されているで、その仕様に従ってやりとりすることになります。
例では人に見やすく改行、インデントを入れていますが、
アプリケーションやネットワーク、I/Oにとっては、無駄なだけなので、
実際には、改行やインデントは入っていないのが一般的です。

HTTPの本文(ボディ)の形式に関しては、HTTPのリクエストヘッダやレスポンスヘッダで指定します。

本文(ボディ)がJSON形式の場合は、以下のようなヘッダを指定、または取得することになります。
```
Content-Type: application/json; charset=utf-8
```
このヘッダをもらった側のアプリは、本文(ボディ)がJSON形式で、かつ、utf-8でエンコードされているとして、
処理することができます。

本文(ボディ)を含む場合は、このヘッダをやり取りする相手と交換すると、適切に処理することができますが、
本文(ボディ)を含まない場合は、特に必要なものではありません。

相手からどのような形式で欲しいかを指定したい場合は、`Accept`や`Accept-Charset`などのヘッダを利用します。

```
Accept: application/json
Accept-Charset: utf-8
```

のような感じです。
やりとりする相手が、この形式に対応していれば、このヘッダの指定が、
相手にとって良いヒントになるはずです。


### 2.1.5 HTTPのレスポンスのステータスコードで成功を判断する

リソースのやりとりにおいて、HTTPのレスポンスに含まれるステータスコードで
成功したかどうかは判断できます。

ほとんどのREST APIにおいては、成功した場合は、
HTTPのステータスコードの、`200 OK`か`204 No Content`を返すように設計されていると思います。
`204 No Content`の場合は、レスポンスに本文(ボディ)が含まれていないことになります。

`200 OK`か`204 No Content`かは、リソースに対する操作によって設計上規定されているはずですが、
`DELETE`メソッドの場合は、リソースの削除であって、特に結果として返すリソースもないので、
`204 No Content`を活用しているREST APIも多いと思います。

**成功した場合の条件は決まっているので**、
**成功しなかった場合はすべて、失敗した**として扱うことになります。

> 失敗したときの条件を確認して、
> 「失敗しなかった場合が、成功」として扱うのは、かなり危うい実装であると思います。
> プログラミングするときに、確認すべきは、まずは、「成功かどうか」であって、「失敗かどうか」ではないはず。

成功しなかった場合に、
失敗した理由に関しては、ステータスコードの値で、おおよその推測が付くように設計されている場合が多いです。
また、失敗理由の詳細が、本文(ボディ)で取得できるように設計されている場合もあります。

# 3. Cisco Webex TeamsのREST API

基本的には、うえで説明したことを、Cisco Webex TeamsのREST APIの場合に、
当てはめていくだけになります。
概要だけ、さくっと記載します。
個別の詳細に関しては、別記事にしていく予定です。

## 3.1. Cisco Webex TeamsのREST APIのURI

Cisco Webex TeamsのREST APIのURIは、以下の2パターンになっています。

* `https://api.ciscospark.com/v1/{リソースの種類}/{リソースのID}`
* `https://api.ciscospark.com/v1/{リソースの種類}`

本記事執筆時点(2018年02月時点)では、APIのバージョンはv1になっており、
すべてのURIは、
`https://api.ciscospark.com/v1/`で始まります。
今後、互換性が崩れるようなバージョンアップが行われる場合は、
`v1`部分が異なるAPIが提供される可能性があります。

## 3.2. Cisco Webex TeamsのREST APIの{リソースの種類}と操作

### 3.2.1. 基本リソース

基本的なリソースと、それぞれ可能な操作は以下の表のようになります。
できると記載されていても、仕組み上、必ず失敗することもあります。
例えば、アプリ自身が投稿したメッセージは削除できますが、任意のメッセージの削除ができるわけではありません(Cisco Webex Teamsのプランや設定によってはできる)。

できないと記載されているものは、Cisco Webex Teamsの機能上からくる仕様となります。
例えば、既存のメッセージを更新することはできません。
また、一括削除するようなAPIは提供されていません。

〇 : できる、× : できない

| リソースの種類 | 説明 | 新規作成 | 詳細取得 | 一覧取得 | 更新 | 削除 |
| :----------- | :--- | :------: | :-----: | :-----: | :--: | :--: |
| people | Cisco Webex Teamsのユーザ  | × | 〇 | 〇 | × | × |
| rooms  | Cisco Webex Teamsのスペース  | 〇 | 〇 | 〇 | 〇 | 〇 |
| memberships | Cisco Webex Teamsのスペース参加者 | 〇 | 〇 | 〇 | 〇 | 〇 |
| messages    | Cisco Webex Teamsのメッセージ | 〇 | 〇 | 〇 | × | 〇 |
| teams       | Cisco Webex Teamsのチーム | 〇 | 〇 | 〇 | 〇 | 〇 |
| team/memberships | Cisco Webex Teamsのチーム参加者 | 〇 | 〇 | 〇 | 〇 | 〇 |
| webhooks | Cisco Webex Teamsで起こったイベント通知用のWebhook | 〇 | 〇 | 〇 | 〇 | 〇 |

リソースの種類をURIに含めてURIを構成したうえで、POST, GET, PUT, DELETEのHTTPメソッドを使ってリソースを操作することになります。
例えば、`rooms`の場合は、以下のようになります。

* 新規作成: `POST https://api.ciscospark.com/v1/rooms`
* 詳細取得: `GET https://api.ciscospark.com/v1/rooms/{スペースのID}`
* 一覧取得: `GET https://api.ciscospark.com/v1/rooms`
* 更新: `PUT https://api.ciscospark.com/v1/rooms/{スペースのID}`
* 削除: `DELETE https://api.ciscospark.com/v1/rooms/{スペースのID}`

Cisco Webex TeamsのREST APIでは、POST、PUTによって、**リソースを新規作成、更新する場合**は、
リクエスト時に、本文(ボディ)をJSON形式で指定して、作成・更新するリソースの内容を指定する必要があります。
それ以外の場合は、本文(ボディ)は指定しません。

**DELETE以外の操作**では、
Cisco Webex TeamsのREST APIのサーバからのレスポンスの本文(ボディ)には、
作成・取得・更新したリソースの内容がJSON形式で含まれます。

**DELETEの操作**では、レスポンスの本文(ボディ)は、通常は含まれませんが、
削除に失敗した場合には、エラーコードとエラー理由がJSON形式で含まれる場合があります。


### 3.2.2. リクエスト時のAuthorizationヘッダ

リクエスト時には、ヘッダで、アプリケーション用に発行されたトークンを指定してリクエストする必要があります。

トークンは、Botアカウント用に発行されたBot専用のトークン、
または、
開発者サイトで登録したIntegrationアプリに対してOAuth2を使って発行されたトークン
を使います。

Authorizationヘッダーに、"Bearer" + " " + "Token文字列"を指定します。

例えば、トークンが、`xyz`だったと仮定すると、

```
Authorization: Bearer xyz
```

のようなAuthorizationヘッダをつけて、APIを呼び出すことになります。