Microsoft Flow を使って connpass の気になる勉強会を SharePoint Online リストに取り込んでみる

# 作成するフローの概要
この記事では、Microsoft Flow を利用して、

* 1 日おきに実行し
* connpass から気になるキーワードが含まれる勉強会を取得し
* 新しいものがあれば SharePoint リストに取り込む

という処理を作成します。

# SharePoint Online にリストを用意する
connpass から取得した勉強会の情報を格納するためのリストを SharePoint Online 側に作成しておきます。

カスタム リストから作成し、下記のような列を追加しておきました。

| 列名 | 列の種類 | 用途 |
|:------------|:-------------|:-------------|
| EventID    | 一行テキスト   | connpass 上のイベント Id を保存 |
| Description    | 複数行テキスト | イベントの説明文を保存 |
| EventURL    | 複数行テキスト | connpass のイベント ページの URL を保存 |
| StartDateTime    | 日時（日付と日時）| イベントの開始日時を保存 |
 

# 1 日おきに実行する
1 日おきに定期的に実行するためには、「スケジュール」を利用します。まずは「スケジュール」をフローに追加します。追加したら、「頻度」を「日」に変更します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/de95764a-f718-0153-1f03-b07cc2c68937.png)

# connpass からデータを取得する
connpass から値を取得するには、REST API が利用できますので、「HTTP」を利用し取得します。

フローに「HTTP」を追加し、「方法」には「GET」を、「URI」には「[https://connpass.com/api/v1/event/?keyword_or=Office%20365&order=3&format=json&count=10](https://connpass.com/api/v1/event/?keyword_or=Office%20365&order=3&format=json&count=10)」といった URL を指定します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/23862508-d3f1-6cd6-022f-285e574add5c.png)

この URL では、「Office 365」に関する勉強会を取得するようにしていますが、URL の「keyword_or」で指定されているキーワードを変更することで、任意のデータを取得可能です。

その他のパラメータは、[connpass API リファレンス](https://connpass.com/about/api/) をご覧ください。

# connpass API の結果をパースする
「HTTP」を利用して取得した REST API からの取得結果は、JSON フォーマットとなっていますが、これを Flow で簡単に扱えるように解析（パース）しておきます。これには「データ操作 - JSON の解析」を利用します。

フローに追加したら、「コンテンツ」には、HTTP からの「本文」を、「スキーマ」には、下記の JSON Schema の定義を入力します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/f957748d-d5ee-988e-af4f-5cc4226dc94a.png)

```json
{
  "properties": {
    "events": {
      "items": {
        "properties": {
          "accepted": {
            "type": "number"
          },
          "address": {
            "type": "string"
          },
          "catch": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "description": {
            "type": "string"
          },
          "ended_at": {
            "type": "string"
          },
          "event_id": {
            "type": "number"
          },
          "event_type": {
            "type": "string"
          },
          "event_url": {
            "type": "string"
          },
          "hash_tag": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "lat": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "type": "number"
          },
          "lon": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "owner_display_name": {
            "type": "string"
          },
          "owner_id": {
            "type": "number"
          },
          "owner_nickname": {
            "type": "string"
          },
          "place": {
            "type": "string"
          },
          "series": {
            "properties": {
              "id": {
                "type": "number"
              },
              "title": {
                "type": "string"
              },
              "url": {
                "type": "string"
              }
            },
            "oneOf": [
              {
                "type": "object"
              },
              {
                "type": "null"
              }
            ]
          },
          "started_at": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "waiting": {
            "type": "number"
          }
        },
        "type": "object",
        "required": [
          "event_url",
          "event_type",
          "owner_nickname",
          "series",
          "updated_at",
          "lat",
          "started_at",
          "hash_tag",
          "title",
          "event_id",
          "lon",
          "waiting",
          "limit",
          "owner_id",
          "owner_display_name",
          "description",
          "address",
          "catch",
          "accepted",
          "ended_at",
          "place"
        ]
      },
      "type": "array"
    },
    "results_available": {
      "type": "number"
    },
    "results_returned": {
      "type": "number"
    },
    "results_start": {
      "type": "number"
    }
  },
  "type": "object"
}
```
この JSON Schema については、「サンプルのペイロードを使用してスキーマを生成する」のリンクをクリックし表示されるダイアログに、REST API から返ってきた JSON を入力すると自動で生成されます。

ただし、null が返ってくる可能性のある項目がある場合には、少し書き換えてあげないと上手く動かないことがあります。今回実際にあったのは、勉強会によってはキャッチやハッシュタグが指定されておらず catch や hash_tag が null になっており、実行時に「"Invalid type. Expected Object but got Null."」といったエラーが返ってきていました。

そのため、例えば、

```json
"catch": {
    "type": "string"
}
```
とあったところを、

```json
"catch": {
    "oneOf": [
        {
            "type": "string"
        },
        {
            "type": "null"
        }
    ]
}
```
とすることで、この値は string か null の可能性もあるよという定義に修正しています。

~~しかしながら大問題があり、このように書き換えた場合には、後続のアクションで GUI から選択ができなくなります…（なんてこった！）、「ワークフロー定義言語」を利用することで値にアクセスできますがそこはまた別の機会に…。~~

このあたりは、API のリファレンスや返り値を見ながら調整する必要がありそうです。

# ループ処理
これで複数件の勉強会に関するデータが取得できたので、件数分のループ処理を回して SharePoint Online のリストへ格納していきます。ループ処理のためには、「Apply to each」を追加し、「以前の手順から出力を選択」に「events」を指定します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/de572651-2675-4e9c-0d59-b9f251112844.png)

# 以前登録したデータとの重複をチェック
毎日実行されて、同じ勉強会が重複して格納されるのは困るので、重複をチェックするロジックを入れておきます。

ループの中で、「SharePoint - 項目の取得」を追加し、「サイトのアドレス」には目的のリストが存在するサイトの URL を、「リスト名」には目的のリストを指定します。

次に、「詳細オプションを表示する」をクリックし展開後、「フィルター クエリ」にはリスト列の「EventID」列でフィルターを掛け、API から取得してきたイベントと同じ ID が登録されているアイテムのみをリストから取得するようにします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/2c1c279d-7db6-1019-9614-f4f652507f32.png)

重複のチェックは、条件分岐で行ないたいと思いますので、「条件の追加」を行ないます。今回指定したい条件は、GUI からクリックポチポチでは設定できないため、「詳細設定モードで編集」に切り替え、次の通りに入力します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/32bc64d4-c40c-5a11-7f0f-2c5b9babb9de.png)

```
@greater(length(body('項目の取得')?['value']), 0)
```

この条件では、SharePoint Online のリストから特定のイベントの ID でフィルタして得られた結果が 0 件よりも多いかどうかをチェックしています。これで、登録済みのイベントの ID と重複するイベントが SharePoint に登録されている場合には、条件を満たし、未登録の場合には条件を満たさないといった分岐になります。

# SharePoint Online のリストにアイテムを登録
SharePoint Online のリストへのアイテムの登録は、「SharePoint - 項目の作成」を追加します。サイトの URL と リストを設定し、各列には REST API から取得した値をそれぞれ設定します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/5770fada-8f53-6d0a-face-9c20055a856a.png)

# 全体像
ここまでの手順を行うと、次のようになります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/7cea0f27-578f-c59c-06b6-8d243c8b7dc0.png)

# 実行結果
データは、こんな感じで SharePoint Online のリストに入ります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/8b43c922-9580-e8a0-e42f-35e6392fcdc8.png)

#さいごに
私のチームでは、こうした Microsoft Flow を含めた Office 365 の利活用について様々ご支援をさせていただいています。お悩みをお持ちの方、ぜひご相談ください。
[Microsoft Office 365 関連サービス | 情報共有・コミュニケーション 内田洋行](http://www.uchida.co.jp/it/products/office365/)