【Contacts IoT】API 仕様とシーケンス図を作成したので公開します

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

テントの中から失礼します、IoT事業部のてんとタカハシです!

コンタクトレンズ使用者を眼障害から守ることを目的として、コンタクトレンズの着脱管理を行う IoT プロジェクトを進めています。 プロジェクトの概要については、下記の記事をご参照ください。

本プロジェクトに関する記事の一覧は下記のページにまとまっています。

概要

コンタクトレンズ着脱管理 API の仕様及び、それぞれのエンドポイントを叩く際のシーケンスを作成しました。開発を進めていく中で変更が加わることは大いにあり得ますが、現時点での設計を公開しようと思います。

API 仕様

取得 & 登録するデータについて、現時点で DB に格納が必須なものに絞っているため、最低限必要なエンドポイントのみ設計しています。また、将来的に複数デバイス登録可能にすることを考慮しています。

See the Pen コンタクトレンズ着脱管理API v0.1.0 by t.takahashi (@iam326) on CodePen.

YAML はこちら
swagger: '2.0'
info:
  version: '0.1.0'
  title: 'コンタクトレンズ着脱管理API'
host: 'xxx.execute-api.ap-northeast-1.amazonaws.com'
basePath: '/v1'
schemes:
  - 'https'
paths:
  /devices:
    get:
      summary: 'デバイスの一覧を取得する'
      consumes:
        - 'application/json'
      produces:
        - 'application/json'
      responses:
        '200':
          description: '成功'
          schema:
            $ref: '#/definitions/GetDevicesResponse'
        '401':
          description: '認証エラー'
        '500':
          description: 'サーバーエラー'
    post:
      summary: 'デバイスを登録する'
      consumes:
        - 'application/json'
      produces:
        - 'application/json'
      parameters:
        - in: 'body'
          name: 'body'
          required: true
          schema:
            $ref: '#/definitions/PostDeviceRequest'
      responses:
        '200':
          description: '成功'
        '401':
          description: '認証エラー'
        '500':
          description: 'サーバーエラー'
  /devices/{deviceId}/wearing/current:
    get:
      summary: '現在のコンタクトレンズ着用状態を取得する'
      consumes:
        - 'application/json'
      produces:
        - 'application/json'
      parameters:
        - in: 'path'
          name: 'deviceId'
          required: true
          type: 'string'
      responses:
        '200':
          description: '成功'
          schema:
            $ref: '#/definitions/GetDeviceWearingCurrentResponse'
        '401':
          description: '認証エラー'
        '500':
          description: 'サーバーエラー'
  /devices/{deviceId}/wearing/stats:
    get:
      summary: 'コンタクトレンズ着用統計データを取得する'
      consumes:
        - 'application/json'
      produces:
        - 'application/json'
      parameters:
        - in: 'path'
          name: 'deviceId'
          required: true
          type: 'string'
        - in: 'query'
          name: 'startDate'
          required: true
          description: |
            日付範囲開始日 (JST)
            ex. 2021-01-01
          type: 'string'
        - in: 'query'
          name: 'endDate'
          required: true
          description: |
            日付範囲終了日 (JST)
            ex. 2021-01-07
          type: 'string'
      responses:
        '200':
          description: '成功'
          schema:
            $ref: '#/definitions/GetDeviceWearingStatsResponse'
        '401':
          description: '認証エラー'
        '500':
          description: 'サーバーエラー'
  /settings/registration-token:
    put:
      summary: 'FCMの登録トークンを登録する'
      consumes:
        - 'application/json'
      produces:
        - 'application/json'
      parameters:
        - in: 'body'
          name: 'body'
          required: true
          schema:
            $ref: '#/definitions/PutSettingsRegistrationTokenRequest'
      responses:
        '200':
          description: '成功'
        '401':
          description: '認証エラー'
        '500':
          description: 'サーバーエラー'
definitions:
  GetDevicesResponse:
    type: 'object'
    required:
      - 'devices'
    properties:
      devices:
        type: 'array'
        items:
          type: 'object'
          required:
            - 'deviceId'
          properties:
            deviceId:
              type: 'string'
  PostDeviceRequest:
    type: 'object'
    required:
      - 'deviceId'
    properties:
      deviceId:
        type: 'string'
  GetDeviceWearingCurrentResponse:
    type: 'object'
    description: '現在のコンタクトレンズ着用状態'
    required:
      - 'nowWearing'
    properties:
      nowWearing:
        description: |
          着用中フラグ
          着用中であれば true となる
        type: 'boolean'
        example: true
      startTimestamp:
        description: '着用開始時間 (Optional)'
        type: 'number'
        example: 1626764818
      endTimestamp:
        description: '着用終了時間 (Optional)'
        type: 'number'
        example: 1626764819
  GetDeviceWearingStatsResponse:
    type: 'object'
    description: 'コンタクトレンズ着用統計データ'
    required:
      - 'wearingDays'
      - 'averageWearingSeconds'
      - 'metircs'
    properties:
      wearingDays:
        description: '着用日数'
        type: 'number'
        example: 7
      averageWearingSeconds:
        description: '平均着用秒数'
        type: 'number'
        example: 21600
      metrics:
        type: 'array'
        description: '並び順は着用日の昇順'
        items:
          type: 'object'
          required:
            - 'wearingDate'
            - 'wearingSeconds'
          properties:
            wearingDate:
              description: '着用日 (JST)'
              type: 'string'
              example: '2021-01-01'
            wearingSeconds:
              description: |
                着用秒数
                未着用の場合は0となる
                着用中のデータは返らない
              type: 'number'
              example: 16920
  PutSettingsRegistrationTokenRequest:
    type: 'object'
    required:
      - 'registrationToken'
    properties:
      registrationToken:
        type: 'string'

シーケンス図

デバイス登録

ユーザーとデバイスを紐付ける際の処理です。

アプリ起動時にデバイス情報を取得して、存在しなかったら登録用の画面を表示します。

FCM登録トークン登録

FCM(Firebase Cloud Messaging)でアプリに通知を送る際に必要なトークンの登録処理です。

アプリ起動時にローカルに保存してある登録済みフラグを取得します。存在しなかったら登録用のエンドポイントを叩きます。FCM 登録トークンはスマホを入れ替えた時に更新が必要なので、DB ではなくローカルに登録済みであるかどうかを示すフラグをセットします。

現在のコンタクトレンズ着用状態表示

下記画面を表示する際の処理です。

デバイス ID に紐づいた最新の着脱データを取得します。

着脱管理テーブルは下記になります。着脱開始時間の降順で1件レコードを取得して、着用終了時間の有無や現時刻との比較で、着用中かどうかを判断します。

コンタクトレンズ着用統計データ表示

下記画面を表示する際の処理です。

デバイス ID に紐づいた着脱データを日付範囲で指定して取得します。DynamoDB を使用している都合、クエリーで集計できないため、Lambda 内で集計処理を組みます。

PlantUML はこちら
= シーケンス

== デバイス登録

[plantuml]
----
@startuml
title デバイス登録
box #f0fff0
  actor "ユーザー" as user
end box
box #f8f8ff
  participant "アプリ" as app
end box
box "AWS" #fff2df
  participant "API Gateway" as api
  participant "Lambda" as lambda
  database "DynamoDB" as db
end box
?-> app: アプリ起動
activate app
app->api: デバイス一覧取得
activate api
api->lambda: デバイス一覧取得
activate lambda
lambda->db: デバイス一覧取得
activate db
db-->lambda: 取得OK
deactivate db
lambda-->api: デバイス一覧
deactivate lambda
api-->app: 200 OK
deactivate api
alt 取得件数が0の場合
  app->app: デバイス登録画面表示
  activate app
  activate user
  user->app: デバイスID入力
  deactivate user
  app->api: デバイス登録
  activate api
  api->lambda: デバイス登録
  activate lambda
  lambda->db: デバイス登録
  activate db
  db-->lambda: 登録OK
  deactivate db
  lambda-->api: 登録OK
  deactivate lambda
  api-->app: 200 OK
  deactivate api
  deactivate app
end
deactivate app
@enduml
----

== FCM登録トークン登録

[plantuml]
----
@startuml
title FCM登録トークン登録
box #f8f8ff
  participant "アプリ" as app
end box
box "AWS" #fff2df
  participant "API Gateway" as api
  participant "Lambda" as lambda
  database "DynamoDB" as db
end box
?-> app: アプリ起動
activate app
app->app: ローカル保存の登録済みフラグを取得
alt 登録済みフラグが存在しない場合
app->api: FCM登録トークン登録
activate api
api->lambda: FCM登録トークン登録
activate lambda
lambda->db: FCM登録トークン登録
activate db
db-->lambda: 登録OK
deactivate db
lambda-->api: 登録OK
deactivate lambda
api-->app: 200 OK
deactivate api
app->app: ローカルに登録済みフラグを保存する
end
deactivate app
@enduml
----

== 現在のコンタクトレンズ着用状態表示

[plantuml]
----
@startuml
title 現在のコンタクトレンズ着用状態表示
box #f8f8ff
  participant "アプリ" as app
end box
box "AWS" #fff2df
  participant "API Gateway" as api
  participant "Lambda" as lambda
  database "DynamoDB" as db
end box
?-> app: 画面遷移
activate app
app->api: 現在の着用状態取得
activate api
api->lambda: 現在の着用状態取得
activate lambda
lambda->db: 最新のレコード1件取得
activate db
db-->lambda: 取得OK
deactivate db
lambda-->api: 現在の着用状態
deactivate lambda
api-->app: 200 OK
deactivate api
app->app: 現在の着用状態を表示する
@enduml
----

== コンタクトレンズ着用統計データ表示

[plantuml]
----
@startuml
title コンタクトレンズ着用統計データ表示
box #f8f8ff
  participant "アプリ" as app
end box
box "AWS" #fff2df
  participant "API Gateway" as api
  participant "Lambda" as lambda
  database "DynamoDB" as db
end box
?-> app: 画面遷移
activate app
app->api: 着用統計データ
activate api
api->lambda: 着用統計データ
activate lambda
lambda->db: 日付範囲指定でレコード取得
activate db
db-->lambda: 取得OK
deactivate db
lambda->lambda: 集計
lambda-->api: 着用統計データ
deactivate lambda
api-->app: 200 OK
deactivate api
app->app: 着用統計データ表示
@enduml
---

Next

アプリ、API の実装を進める段階に入っています。進捗ありましたらブログに書いていきます。

おわりに

設計している途中で細かい挙動などを検討、メンバーと考えを共有することができました。Android アプリの開発はほぼ初心者ですが、とりあえず動かすの精神で実装頑張ります。

今回は以上になります。最後まで読んで頂きありがとうございました!