SurveyMonkeyのAPIでアンケート結果取得

## はじめに
初めまして、[ｋ．ｓ．ロジャース](https://www.wantedly.com/companies/ks-rogers)の西谷です。
先月は開発を進めていく中で[SurveyMonkey](https://jp.surveymonkey.com/)を利用する話があり、API周りを調査しておりました。
公式ドキュメントは充実しておりますが、日本語の記事がなく苦労した覚えがあったため、アンケート回答の取得方法について共有出来たらと思います。
※ SurveyMonkyのAPIを利用するにはプレミアプランが必要です。

間違い・助言等があればコメントにてお知らせいただけたらと思います。


## SurveyMonkeyとは
SurveyMonkeyはアンケート管理システムで、Web上でアンケートの作成・収集・集計を一括で行うことが出来ます。

<img width="1439" alt="68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3237343637342f66626334313136302d666136342d313935322d326161652d6164626533366162323839652e706e67.png" src="https://qiita-image-store.s3.amazonaws.com/0/274674/71ed93f6-b17a-b7f2-1059-a5018fa0e192.png">
このようにGUIからアンケートを作成できます。
アンケート作成後はメール・URL・SNSなどから送信することができます。

今回は画面で作成したアンケートに回答したときに、APIでシステム側に通知する仕組みを紹介したいと思います。


## SurveyMonkeyのデータ構造
SurveyMonkeyのデータ構造は下図のようになっています。
APIからアンケートの内容とユーザの回答内容を知ることが出来ます。
<img width="720" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/274674/ca6ccd9c-8767-f163-e8f1-d80c0b57f6ca.png">


## アプリの登録
1. [開発者画面](https://developer.surveymonkey.com/apps/)の**Add a New App**から新規アプリを作成します。
<img width="788" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/274674/96fdd2b6-557c-9624-3c7a-aacd917f6073.png">

2. 作成後、**SETTINGS**画面からScopesを設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/274674/a376008e-44bf-7c90-4aaf-2f86cff5a3f5.png)
利用APIに応じて権限をRequiredに変更します。
不足している場合はAPIで`Permission Error`が出ますので、エラーを見てから変更でもいいかもしれません。



## OAuth認証
登録アカウントの認証を行い、アクセストークンを取得します。

### APIでアクセストークン取得

1. 以下APIを実行します
    [GET] https://api.surveymonkey.com/oauth/authorize

    | パラメータ    | 値                              |
    |---------------|---------------------------------|
    | response_type | code                            |
    | redirect_uri  | SETTING画面のOAuth Redirect URL |
    | client_id     | SETTING画面のClient ID          |



1. SurveyMonkeyにログインすると、`redirect_uri`にcodeが届きます。

1. トークン発行のAPIを実行します

RESTクライアントで`code`の一部がエスケープされて認証失敗する場合があるのでご注意ください。
[POST] https://api.surveymonkey.com/oauth/token

```json
{
	"client_id": {SETTING画面のClient ID},
	"client_secret": {SETTING画面のSecret},
	"code": {redirect_uriに届いたcode},
	"redirect_uri": {SETTING画面のOAuth Redirect URL},
	"grant_type":"authorization_code"	
}
```

成功すると以下のようなレスポンスが得られますので、`access_token`を保存します。

```json
{
  "access_token": "hogehoge",
  "token_type": "bearer",
  "access_url": "https:\/\/api.surveymonkey.com",
  "expires_in": null
}
```

現時点(2019/2)では、SurveyMonkeyのアクセストークンは無期限であるが、[有効期間が追加される可能性](https://developer.surveymonkey.com/api/v3/#token-expiration-and-revocation)があります。

## APIからアンケート結果収集
ログインしてアクセストークンを取得出来ましたので、アンケート取得について説明します。
取得手順の概要は以下になります。
1. 回答を収集するアンケートのIDを取得
2. アンケートに対してWebhookを登録
3. 回答があればコールバックを受け取り、APIから回答内容を取得

以降のAPIはリクエストのHeaderに`Authorization: Bearer アクセストークン`を追加して実行します。

### アンケートID取得
回答を収集するアンケートのIDのを取得します。
アンケートIDはブラウザから直接確認する方法はないため、APIで取得します。([DevToolsからは取得出来ます](https://stackoverflow.com/questions/23619735/surveymonkey-how-do-you-determine-a-surveys-id))

[GET] https://api.surveymonkey.net/v3/surveys

| パラメータ | 値                            | デフォルト値 |
|------------|-------------------------------|-----------|
| per_page   | 1ページに表示する数(最大1000) | 50      |
| page       | 表示ページ                    | 1      |
| title      | タイトルの絞り込み            | なし      |


レスポンスはこのようになります。
こちらのIDをWebhookに登録すればコールバックで回答を知ることが出来ます。

```json
{
  "per_page": 50,
  "total": 100,
  "data": [
    {
      "href": "https:\/\/api.surveymonkey.net\/v3\/surveys\/12345",
      "nickname": "",
      "id": "12345",
      "title": "アンケート1"
    },
    {
      "href": "https:\/\/api.surveymonkey.net\/v3\/surveys\/67890",
      "nickname": "",
      "id": "67890",
      "title": "アンケート2"
    }
    (省略)
  ],
  "page": 1,
  "links": {
    "self": "https:\/\/api.surveymonkey.net\/v3\/surveys?page=1&per_page=50",
    "last": "https:\/\/api.surveymonkey.net\/v3\/surveys?page=20&per_page=50",
    "next": "https:\/\/api.surveymonkey.net\/v3\/surveys?page=2&per_page=50"
  }
}
```

### Webhook登録
以下APIでWebhookの登録ができます。

[POST] https://api.surveymonkey.net/v3/webhooks

```json
{
  "name": {Webhook名},
  "event_type": "response_completed",
  "object_type": "survey",
  "object_ids": [{アンケートID1}, {アンケートID2} ...],
  "subscription_url": {コールバック先}
}
```
`201 Created`のレスポンスが帰ってこれば成功です。

注意点としては登録時にSurveyMonkeyから`subscription_url`に対して、HEADリクエストで疎通確認を行います。
ですので開発側で、`subscription_url`のHEADで受信し、`200 OK`のレスポンスを返すように準備する必要があります。
PHPであれば以下のようなコードで大丈夫です。

```php
public function head_index()
{
    return $this->response(null, $http_code = 200);
}
```

また、疎通確認のためにローカルで開発する場合はサーバを外部公開する必要があります。
[ngrok](https://ngrok.com)を利用すると簡単にローカル環境を外部に公開できます。

### コールバックから回答内容を取得
Webhook登録後、ユーザが回答完了後にSurveyMonkeyから`subscription_url`にPOSTのリクエストが送信されます。

```json
{
    "event_datetime": "2019-01-01T00:00:00.000000+00:00",
    "resources": {
        "respondent_id": "123456789",
        "recipient_id": "0",
        "user_id": "123456789",
        "collector_id": "123456789",
        "survey_id": "123456789"
    },
    "name": "WebhookName",
    "object_id": "123456789",
    "filter_id": "123456789",
    "event_id": "123456789",
    "object_type": "response",
    "filter_type": "survey",
    "event_type": "response_completed"
}
```

次にresponseの内容を取得します。
[GET] https://api.surveymonkey.net/v3/collectors/{collector_id}/responses/{respondent_id}/details
レスポンスは長いので一部省略しますが、`pages`の部分から回答が分かります。

```json
"pages": [
    {
      "id": "12345", #page_id
      "questions": [
        {
          "id": "12345", #question_id, 
          "answers": [
            {
              "choice_id": "123456789"
            }
          ]
        }
      ]
    }
]
```

`choice_id`が分かりましたので、質問詳細を取得して`choice_id`が一致するchoicesを探します。
[GET] https://api.surveymonkey.net/v3/surveys/{survey_id}/pages/{page_id}/questions/{question_id}

```json
{
    (省略)
    "choices": [
      {
        "quiz_options": {
          "score": 0
        },
        "visible": true,
        "text": "回答1",
        "position": 1,
        "id": "123456789"
      },
      {
        "quiz_options": {
          "score": 0
        },
        "visible": true,
        "text": "回答2",
        "position": 2,
        "id": "987654321"
      },
      {
        "quiz_options": {
          "score": 0
        },
        "visible": true,
        "text": "回答3",
        "position": 3,
        "id": "192837465"
      }
    ]
    (省略)
}
```

この例の場合はユーザが**回答1**を選択したことがわかります。
後は自作システムに回答内容の保存、選択肢によって動作分岐などが出来ると思います。

## おわりに
長くなりましたが、SurveyMonkeyのAPIでアンケート回答の取得方法を紹介させて頂きました。
もっとシンプル方法や間違いがあればご指摘頂けたらと思います。

### Wantedlyでもブログ投稿してます
Techブログに加えて会社ブログなどもやっているので、気になった方はぜひ覗いてみてください。
https://www.wantedly.com/companies/ks-rogers