Oura API V2 を読み解いて、Datadog にヘルスケアデータを連携する

## はじめに
こんにちは、Datadog Japan で Sales Engineer をしている [**AoTo**](https://qiita.com/AoTo0330) です。

この記事は **[<font color="#6495ED">AoTo Advent Calendar 2023</font>](https://qiita.com/advent-calendar/2023/aoto) 10日目**の記事です。

:::note info
この記事は完全に趣味の記事です。Oura Ring や Datadog を個人で利用している方は是非最後までお読みください。
:::

みなさん、[**Oura Ring**](https://ouraring.com/) はご存知でしょうか？　Oura Ring は フィンランドのヘルスケア企業 Oura Health Oy によって開発された、睡眠と身体活動を追跡するために使用されるスマートリングです。

日本では Oura Ring [Gen2(第2世代)](https://support.ouraring.com/hc/en-us/articles/360025570153-Previous-Oura-Ring-Generations#h_01H55VMXAS43Q6NAK6Y6DX07BV) の頃から広まり、現在は [Gen3(第3世代)](https://support.ouraring.com/hc/en-us/articles/4409072131091-Oura-Ring-Generation-3) のみが販売されています。Oura Ring によって睡眠時間や睡眠の質をはじめ、日中の活動量から最近ではストレス量までを可視化することができます。

現在これらのヘルスケアデータは [**Oura API V2**](https://cloud.ouraring.com/v2/docs) でエクスポートすることができるため、今回は <INS>Oura API V2 を利用して、Observability プラットフォームである Datadog にデータを連携</INS>してみました。

## Oura API V2 を読み解く
Oura は開発者向けにヘルスケアデータを取得できる [**Oura API V2**](https://cloud.ouraring.com/v2/docs) を提供しています。追加のヘルスケアデータや機能により [**Oura API V1**](https://cloud.ouraring.com/docs/) からリビジョンされ、V1 は **2024年1月22日廃止**されます。

まずは、この **API V2** の仕様を簡単に読み解いていきます。

### ドキュメント
API の仕様は [Oura API Documentation(2.0)](https://cloud.ouraring.com/v2/docs) か [JSON 形式](https://cloud.ouraring.com/v2/static/json/openapi-1.11.json)のダウンロードでの閲覧が可能です。
V2 のドキュメントはデータアクセスと認証方法から始まり、各データタイプ毎に取得方法が説明されています。

### データアクセスと認証
各ヘルスケアデータは[**パーソナルアクセストークン**](https://cloud.ouraring.com/personal-access-tokens)を使用して API 経由で取得が可能です。このトークンを取得するためには、個人のアカウントにアクセスする必要がありますが、Oura Ring を利用していれば**必ず**発行しているので特に問題はありません。個人利用をする場合は、ここまでで問題ありません。

複数人のデータを取得するようにアプリケーションを構成する場合、デフォルトではユーザー数は**10人に制限**されています。商用利用の場合は、**[Oura API Ageement](https://cloud.ouraring.com/legal/api-agreement) に同意して[審査のための申請](https://cloud.ouraring.com/oauth/applications/)の情報を入力して送信する**必要があります。

認証は **OAuth2 プロトコル**か[**パーソナルアクセストークン**](https://cloud.ouraring.com/personal-access-tokens)を直接使用しての認証方法を選択できます。今回は簡易的なデータ連携のため、そのままトークンを利用することにします。アクセストークンを利用する場合は、リクエストヘッダーに以下のように含める必要があります。

```http
GET /v2/usercollection/personal_info HTTP/1.1
Host: api.ouraring.com
Authorization: Bearer <token>
```

:::note warn
`Authorization: Bearer`の`Bearer`は必須の文字列となるので、トークンのみとしないように注意が必要です。
:::

### レスポンスコード
各データタイプに共通の[Oura API のレスポンスコード](https://cloud.ouraring.com/v2/docs#section/Oura-HTTP-Response-Codes)として想定されているのは`200`, `400`, `401`, `403`, `404`, `422`, `429`の7つです。

特に`429`となる場合は、 **5分間に5000リクエスト**のレート制限を超えていることとなるため注意が必要です。取得方法やアプリケーションの仕様上このレート制限を超える可能性がある場合は、Oura API サポート(api-support@ouraring.com)に連絡する必要があります。

### API の仕様
当たり前ですが、Oura API V2 各ヘルスケアデータの**取得のみ**が可能で、ほぼ全ての API は **GET のみ**となっています。それぞれのデータタイプにおいて単一のデータか複数データを指定して取得できます。

API V2 は`baseUrl`として`https://cloud.ouraring.com /v2/usercollection/`を利用します。その後ろにデータタイプと取得範囲を指定する形になります。

**Multiple** でデータを取得する際は、`start_date`と`end_date`を指定することでその期間のすべてのデータを取得できます。それぞれの日付は`YYYY-MM-DD`形式で指定する必要があります。

**Single** でデータを取得する際は、`{document_id}`を指定する必要があります。この`{document_id}`は単一のデータに対して割り振られる一意の ID で、`/^[a-zA-Z0-9]{8}-[0-9]{4}-[0-9]{4}-[a-zA-Z]{4}-[a-zA-Z0-9]{12}$/`の形で表されます。[^1]
[^1]: この`{document_id}`の割り振り方には規則性がないため、未知のデータを取得することに向いていません。

#### データタイプと API 一覧

| Neme | Multiple | Single |
| --- | --- | --- |
| [Daily Activity](https://cloud.ouraring.com/v2/docs#tag/Daily-Activity-Routes) | /daily_activity | /daily_activity/{document_id} |
| [Daily Readiness](https://cloud.ouraring.com/v2/docs#tag/Daily-Readiness-Routes) | /daily_readiness | /daily_readiness/{document_id} |
| [Daily Sleep](https://cloud.ouraring.com/v2/docs#tag/Daily-Sleep-Routes) | /daily_sleep | /daily_sleep/{document_id} |
| [Daily Spo2](https://cloud.ouraring.com/v2/docs#tag/) | /dailiy_spo2 | /dailiy_sp02/{document_id} |
| [Heart Rate](https://cloud.ouraring.com/v2/docs#tag/Heart-Rate-Routes) | - | /heartrate |
| [Personal Info](https://cloud.ouraring.com/v2/docs#tag/Personal-Info-Routes) | /presonal_info | - |
| [Rest Mode Period](https://cloud.ouraring.com/v2/docs#tag/Rest-Mode-Period-Routes) | /rest_mode_period | /rest_mode_period/{document_id} |
| [Ring Configuration](https://cloud.ouraring.com/v2/docs#tag/Ring-Configuration-Routes) | /ring_configuration | /ring_configuration/{document_id} |
| [Session](https://cloud.ouraring.com/v2/docs#tag/Session-Routes) | /session | /session/{document_id} |
| [Sleep](https://cloud.ouraring.com/v2/docs#tag/Sleep-Routes) | /sleep | /sleep/{document_id} |
| [Sleep Time](https://cloud.ouraring.com/v2/docs#tag/Sleep-Time-Routes) | /sleep_time | /sleep_time/{document_id} |
| [Tag](https://cloud.ouraring.com/v2/docs#tag/Tag-Routes) | /tag | /tag/{document_id} |
| [Workout](https://cloud.ouraring.com/v2/docs#tag/Workout-Routes) | /workout | /workout/{document_id} |

#### Webhook サブスクリプション
上記の API とは異なり、Oura API に [**Webhook サブスクリプション**](https://cloud.ouraring.com/v2/docs#tag/Webhook-Subscription-Routes)を作成することで、Webhook を利用してほぼリアルタイムに Oura データの更新を受信できる仕様が用意されています。

Webhook サブスクリプションを利用するには、[Create Webhook Subscription](https://cloud.ouraring.com/v2/docs#operation/create_webhook_subscription_v2_webhook_subscription_post) から行う必要があります。この API にはリクエストボディに`application/json`形式で、`callback_url`でサブスクリプションをする URL、`verification_token`で認証トークンを、`event_type`でイベントタイプを、`data_type`で取得するデータタイプを指定します。

```mermaid
graph LR
  Start([POST /v2/webhook/subscription</br>へリクエスト])-->A([Oura API がサブスクリプション</br>を作成する])
  A-->B{リクエストは</br>認証されたか}
  B-->|yes|C([request.callback_url に</br>GET で認証を行う])
  B-->|no| End([Faliue])
  C-->D{リクエストは</br>認証されたか}
  D-->|yes|E([POST で subscription id</br>とデータを送信する])
  D-->|no| End([Faliue])
  E-->End2([Success])
```

この Webhook サブスクリプションを作成した時に渡したデータを元に、Oura API はデータが更新される毎に最新のデータをサブスクリプションをする元に POST します。この内容を更新したい場合は、[Update Webhook Subscription](https://cloud.ouraring.com/v2/docs#operation/update_webhook_subscription_v2_webhook_subscription__id__put) を利用できます。

Datadog に連携をする場合、データタイプやフォーマットを Datadog のメトリクス・ログに合うように考慮する必要があるので、今回はこの方法を利用せずに特定のデータを明示的に指定して取得します。

## Datadog に連携する
Datadog にデータを連携するためには、[**Datadog API**](https://docs.datadoghq.com/ja/api/latest/) を利用することができます。データ連携を行うために、[**Oura API V2**](https://cloud.ouraring.com/v2/docs) では **cURL, Python, JavaScript, Java** でのサンプルコードを提示しています。

[AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) のようなサーバレス関数を [Amazon EventBridge Scheduler](https://docs.aws.amazon.com/scheduler/latest/UserGuide/what-is-scheduler.html) を利用して定期的に実行するイベントドリブンアーキテクチャの構成を取ることもできますが、<INS>Datadog と Oura API のみで完成させる方法</INS>はあるのでしょうか。

**はい、あります。**

[**Datadog Workflow Automation**](https://docs.datadoghq.com/ja/service_management/workflows/) を使用することで、<INS>ローコード UI を用いて **Oura API V2 を利用したデータの取得**と **Datadog API を利用したデータの記録**</INS>が行えます。

### Datadog Workflow Automation とは
[**Datadog Workflow Automation**](https://docs.datadoghq.com/ja/service_management/workflows/) は Datadog の SaaS プラットフォーム上で作成できる、ローコードの自動化ツールです。公式ドキュメントの内容を引用すると、**HTTP アクション**や**JavaScript データ演算子**を定義できるため、<INS>Oura API V2 へ curl で取得したデータを Datadog の形式に変換して Datadog API を用いて保存</INS>できます。

> HTTP アクションや JavaScript データ演算子などの Workflow 固有のアクションに加え、複数のツールにまたがる 400 以上のアクションを提供します。これらのアクションにより、フローで必要とされるあらゆるタスクを実行することができます。

### 今回作成する Workflow
今回は Oura ヘルスケアデータの中から、タイプの異なる睡眠サマリーと心拍数のデータを取得します。

:::note info
**Sleep データ**と **Heart Rate データ**は、それぞれイベントとメトリクスとして記録します。
:::

どちらも①トリガーで Workflow を起動 ②日時情報の生成 ③Oura API V2 によるヘルスケアデータの取得 ④Datadog API Action によるデータの記録の順で行います。それぞれ、①スケジュールトリガー ②JavaScript アクション ③HTTP リクエスト ④Datadog アクションを利用します。

![HeartRateforOura.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/25268597-3254-9697-751c-a51ae41da685.jpeg)

#### ① Workflow スケジュールトリガー
[Workflow のトリガー](https://docs.datadoghq.com/ja/service_management/workflows/trigger/)には、[Workflow ページや Dashboard からの手動トリガー](https://docs.datadoghq.com/ja/service_management/workflows/trigger/#ワークフローを手動でトリガーする)・[Monitor や Security Signal からの自動トリガー](https://docs.datadoghq.com/ja/service_management/workflows/trigger/#ワークフローをモニターからトリガーする)・[Schedule による定期実行](https://docs.datadoghq.com/ja/service_management/workflows/trigger/#ワークフローをスケジュールでトリガーする)が可能です。

今回は、定期的に Workflow を実行して Oura API V2 からヘルスケアデータを取得したいため、[Schedule による定期実行](https://docs.datadoghq.com/ja/service_management/workflows/trigger/#ワークフローをスケジュールでトリガーする)を選択します。単一の Workflow にトリガーは1つしか設定できませんが、手動のトリガーは別途 Workflow ページから実行したり Dashboard に設定したりすることができます。

:::note info
今回は**Sleep データ**を日次で、 **Heart Rate データ**を5分毎に取得します。
:::

#### ② 日時生成 JavaScript アクション
現在のところ Datadog Workflow Automation では日時データをアクションの実行から取得できないため、カスタム JavaScript アクションを用いて Oura API V2 で用いられる`YYYY-MM-DD`形式で、実行時点の日付と前日の日付を取得します。[^2]
[^2]:JavaScript 初心者なので、改善点がありましたらご指摘ください🙇

今回は Oura Ring のタイムゾーンを`Asia/Tokyo`としていますので、`JST`のタイムゾーンでの日付を取得するようにしています。 

```GetDate.js
function formatDateJST(dt) {
  const offset = dt.getTimezoneOffset() * 60000;
  const dateInJST = new Date(dt.getTime() - offset + (9 * 60 * 60000)); // JSTはUTC+9

  return `${dateInJST.getFullYear()}-${String(dateInJST.getMonth() + 1).padStart(2, '0')}-${String(dateInJST.getDate()).padStart(2, '0')}`;
}

function getDatesJST() {
  const today = new Date();
  const todayInJST = formatDateJST(today);

  const yesterday = new Date(today.setDate(today.getDate() - 1));
  const yesterdayInJST = formatDateJST(yesterday);

  return {
    TodayDate: todayInJST,
    YesterdayDate: yesterdayInJST
  };
}

return getDatesJST();
```
:::note warn
Datadog Workflow 上で実行される JavaScript アクションは、UTC ±0 が前提となります。
Datadog プラットフォーム上の時間設定は[Organization Settings] > [General] > [Preferences] > [Monitors Time Zone Preference]から設定が可能ですが、名前の通り現在のところは [Datadog Monitor](https://docs.datadoghq.com/ja/monitors/configuration/) にのみ反映されます。
:::

#### ③ Oura API V2 HTTP リクエストアクション
前述の通り、Oura API には`baseUrl`として`https://cloud.ouraring.com /v2/usercollection/`を共通して利用しています。その後ろに取得するデータタイプと、リクエストパラメーターを`?start_date=YYYY-MM-DD&end_date=YYYY-MM-DD`形式で指定します。

さらに、HTTP リクエストアクションは、[Connection にアクセストークンを使用した認証設定](https://docs.datadoghq.com/ja/service_management/workflows/actions_catalog/generic_actions/#http-token-auth-接続の作成)を反映できます。ここで設定した Token は Token Name のみ後から参照でき、Token Value は全ての Datadog ユーザーに対してマスクされます。

<details><summary>Connection 設定画面</summary>

![ConnectionAuth.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/4cef190c-d7e0-155e-c29b-82b5e97c678c.jpeg)

</details>

この Connection を設定することで、データタイプとパラメーターを指定するだけで、共通する API リクエストを実行することができます。ここで取得したデータは別のアクションで、[**コンテキスト変数**](https://docs.datadoghq.com/ja/service_management/workflows/build/#コンテキスト変数)の一種である**ステップ出力変数**として`{{ Steps.<HTTP アクション名>.<オブジェクト名>.<データ名> }}`のように指定することができます。

今回は、それぞれの HTTP アクションを`GET_SLEEP`と`GET_HEART_RATE`のように命名しています。

#### ④ データ記録 Datadog アクション
最後に、[Datadog API](https://docs.datadoghq.com/api/latest/) を利用したデータの記録を行う Datadog アクションです。イベントの登録には [**Create Event**](https://docs.datadoghq.com/ja/service_management/workflows/actions_catalog/events_createevent/) をメトリクスの登録には [**Submit Metric**](https://docs.datadoghq.com/ja/service_management/workflows/actions_catalog/metrics_submitmetric/) を利用できます。他にも、[Datadog API](https://docs.datadoghq.com/api/latest/) に準じた様々な操作が可能です。

こちらでも同様に、Connection を作成する際に Datadog の [API Key と Application Key](https://docs.datadoghq.com/ja/account_management/api-app-keys/) を登録します。[カスタムサブドメイン](https://docs.datadoghq.com/ja/account_management/multi_organization/#カスタムサブドメイン)を設定してあっても対応可能です。

ここでは登録するイベントやメトリクスの名前を決定したら、取り出すデータを見つけ出し、ステップ出力変数として指定できます。

今回は、睡眠イベントデータをテキストとして`{
{{ Steps.Get_Sleep.body }}
}`のように(雑に)全て記録し、心拍メトリクスデータを`oura.heartrate`と命名し値を`{{ Steps.Get_Heart_Rate.body.data.[0].bpm }}`タグを`conciousness: {{ Steps.Get_Heart_Rate.body.data.[0].source }}`のように最新のオブジェクトのみを参照して記録しました。

### 取得できたデータ
取得できたデータはそれぞれ、睡眠イベントデータは[Service Mgmt] > [Event Management] から、心拍メトリクスデータは[Metrics] > [Explorer]から参照できます。

<details><summary>取得できたデータ</summary>

![SleepEvents.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/68a37621-26d8-b010-f2c5-43604af0096f.jpeg)

![HeartRateMetrics.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/fc045b17-ccab-eecb-9ddd-7e913f237571.jpeg)

</details>

データの形式は今回の内容に限らずログなどの形式にもできますが、データの検索性や歌詞性を高めるために、適切な[タグ付け](https://docs.datadoghq.com/ja/getting_started/tagging/)が重要となってきます。

## おわりに
3年以上愛用している Oura Ring のヘルスケアリングのデータを Datadog で見れないかなという思いで検証してみたのがきっかけでした。

Datadog ではこのように自由に様々なデータソースからのデータを連携・収集し、可視化を行うことができます。もちろん、組み込みでの設定の他にも現在では750を超える[インテグレーション](https://docs.datadoghq.com/integrations/)が提供されているため、ご自身が連携したいものが含まれていないか確認してみてください🐶

Oura Ring もまた、個人のヘルスケアデータを可視化するパーソナルオブザーバビリティツールとして、常に精密な情報をわかりやすく提供してくれます。健康が気になってきたという方は、この機会にクリスマスプレゼントとして買ってみてはいかがでしょうか💍[^3]
[^3]: 本件は個人のおすすめであり、所属する企業や商品の PR ではございません。