Closed21

SSSAPI を試す

hankei6kmhankei6km

面白そうと思ったところ。

設定用 API

(ローカルのサーバー以外で)個人利用アプリ向けに設定用 API など追加しようとするとわりとハードルが高い(認証やらコストやら)。

以前に個人用のウェブアプリの設定を外部に保存するためにうだうだ書いたメモ。
https://hankei6km.github.io/mardock/deck/draftlint-config-external

この辺に利用できるのでは。

AppSheet との併用

おそらく SSSAPI の方針に反するとは思うのだが。

スプレッドシートの更新 UI を AppSheet で作成し、API 部分に SSSAPI を利用すると楽ができるのではという期待。

ここで「いやいや AppSheet でも REST API があるじゃない」となるのだが、「AppSheet の REST API はクセが強い」ので「シンプルな SSSAPI の方がより楽をできるのでは」ということになる(という願望)。

https://hankei6km.github.io/mardock/deck/use-appsheet-like-headless-cms

以下は現状で AppSheet の API を使う場合。

AppSheet のみ

SSAPI が間に入ると以下のように AppSheet の API を使うことがなくなる(はず)なので、少なくとも発動条件がわからない429 に悩まされることはなくなるのかなと。

SSSAPI との併用

その他

以下のスクリーンショットを見たときに「これは説得力ありますわ」と思ったので。

スプレッドシートの画面でコンテンツを入力しているところ説明しているスクリーンショット
説得力のある 1 枚

https://sssapi.app/articles/20211020_usacese_news

hankei6kmhankei6km

利用開始

ユーザー登録のようなものなく Google アカウントでログインする。

ここで面白いのは「権限を付与する必要はない」ということ。

この手のサービスだとだいたいは「Google スプレッドシートのすべてのスプレッドシートの参照、編集、作成、削除」などを要求されるが、SSAPI ではそれがない。

ではどうするのかというと「スプレッドシートを SSSAPI のエージェントユーザーと共有」することで解決していた。

というわけで Google アカウントでログインするだけでユーザー登録は完了した。

hankei6kmhankei6km

API 追加

ドキュメントの通りでとくに引っかかるところはなかった。

https://sssapi.app/help/add_api

今回は以下のスプレッドシートを使っている。フィールド名などの扱いが気になったので日本語多めにしてある。

API 追加に利用したスプレッドシートが表示されているスクリーンショット。カラム名に日本語を利用、図形描画でテキストボックスを追加してある
利用したスプレッドシート

hankei6kmhankei6km

API を使ってみる

設定画面を開くと API の URL が確認できる。

API 設定画面で URL が表示されている部分のスクリーンショット
API の URL 確認

ブラウザー

URL クリックするとブラウザーで JSON のレスポンスを確認できる。

ブラウザーで API のレスポンスを確認しているスクリーンショット
JSON が表示される

また、左下の「Test Tun」クリックすると「API呼び出しテスト」画面になる。

API 呼び出しテスト画面で API のレスポンスを確認しているスクリーンショット
API レスポンスなどが表示できる

CLI

curl などで利用可能。

結果
$ curl -s  'https://api.sssapi.app/XXXXXXXX-XXXX' | jq
[
  {
    "項目 1": 10,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 20,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 30,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  }
]
hankei6kmhankei6km

API の認証

認証済みドメイン

デフォルトの認証済みドメイン。

API の設定画面で「認証済みドメイン」の項目を表示しているスクリーンショット
デフォルトの認証済みドメイン

https://sssapi.app/help/allow_domain/

Access Token を使う予定なのですべて削除。

アクセスできなくなくる。

$ curl -s  'https://api.sssapi.app/XXXXXX_XXXXXX-X' | jq
{
  "error": {
    "message": "'api.sssapi.app' is not allowed."
  }
}

hankei6kmhankei6km

Access Token

追加

トークンはユーザーの設定画面が行う。個別の API にだけ有効なトークンも追加できる。

トークンを生成(追加)するためのダイアログが表示されているスクリーンショット

選択している API は後から変更できるが、トークンの内容は再表示できない。

利用

Authorization リクエストヘッダーでトークンを渡すことで利用できる。

$  curl -s -H 'Authorization: token XXXXXXXXXX' \
     https://api.sssapi.app/XXXXXXXXX | jq
[
  {
    "項目 1": 10,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },

 snip...

https://sssapi.app/help/api_access_token/

hankei6kmhankei6km

データを更新する

API に利用しているスプレッドシートを更新してみる。

手動更新

まずはスプレッドシートを更新する。

スプレッドシートを更新して行の追加などを行った状態のスクリーンショット
行の追加など行う

この時点は API からのレスポンスは更新されない。

$  curl -s -H 'Authorization: token XXXXXXXXXX' \
     https://api.sssapi.app/XXXXXXXXX | jq
[
  {
    "項目 1": 10,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 20,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 30,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  }
]

API の設定画面から「Update」をクリックすると API が再ビルドされてレスポンスも変化する。

API の設定画面の「Update」ボタンが表示されているスクリーンショット
Update をクリック

しばらく待つと更新が完了し Build log で確認できる。

Build log に今回の更新が追加されているスクリーンショット
Build log が増えている

Build log のプレビューで新しいレスポンスを確認できる。

Build log のプレビューで新しいレスポンスを確認しているスクリーンショット
新しいレスポンスを確認

実際に API を実行しても更新が確認できる。

結果
$  curl -s -H 'Authorization: token XXXXXXXXXX' \
     https://api.sssapi.app/XXXXXXXXX | jq
[
  {
    "項目 1": 10,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 20,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 30,
    "項目 2": "ここを更新",
    "項目 3": "abc"
  },
  {
    "項目 1": 40,
    "項目 2": "これは追加",
    "項目 3": "abc"
  }
hankei6kmhankei6km

自動更新

API の設定で自動更新を ON にしておくとスプレッドシート更新時に API が自動的にビルドされるようになる。

API の設定で自動更新を ON にしたスクリーンショット

自動でビルドされた項目が表示されている Build log のスクリーンショット

少し試した限りでは極端に「待たされた」と感じることはなかった。

その後、連続して保存がかかると更新がされなくなることがあった。
だいたい前回の更新から 3 分ほど待つと更新される。
スプレッドシートを一旦閉じて開くと更新されるようになる。

更新間隔に制限がある?

追記: SSSAPI 運営の方から補足いただきました。

この辺の挙動は Google Drive API の変更検知機能の仕様によるそうです(改善も検討されているそうです)。

https://sssapi.app/help/api_option/#自動更新

hankei6kmhankei6km

API のクエリーパラメーター

とりあえずページネーションを試してみる。

とくに問題なく実行できる。

これは個人的にはわりとうれしい、AppSheet の API だと offest に該当する機能がわからなかったので。

追記。
トータルの件数が不明なので終端の判定は「limit よりも少ない件数なら EOF」とすることになるか?現在検証中。

試してみた、offset 位置から取得できる件数が少なければ limit までは取得されない。よって limit よりも少ない件数なら EOF と判断できる。

$ curl -s "https://api.sssapi.app/XXXXXX?limit=2&offset=2" | jq

[
  {
    "項目 1": 30,
    "項目 2": "ここを更新",
    "項目 3": "abc"
  },
  {
    "項目 1": 40,
    "項目 2": "これは追加",
    "項目 3": "abc"
  }
]
hankei6kmhankei6km

レコードの手動並べ替え

各種 Headless CMS について調べたときに「レコードを手動で並べ替える」ことができるサービスが意外と少なかった。

Contetful、GraphCMS、microCMS、prsimic の中では microCMS だけが管理画面のレコード一覧で並べ替えが可能だった(Storyblok でも可能なようだが詳細は試していない)。あとのサービスではモデルを参照関係にして参照されているレコードを並べ替えるような対応が必要となった。

https://zenn.dev/hankei6km/articles/test-collage-cms-content

SSSAPI はスプレッドシートを直接編集するのでここは期待していたがもちろん可能だった。

スプレッドシートで行を並べ替えた状態のスクリーンショット
行を並べ替えた

$  curl -s -H 'Authorization: token XXXXXXXXXX' \
     https://api.sssapi.app/XXXXXXXXX | jq
[
  {
    "項目 1": 10,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 40,
    "項目 2": "これは追加",
    "項目 3": "abc"
  },
  {
    "項目 1": 20,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 30,
    "項目 2": "ここを更新",
    "項目 3": "abc"
  },
  {
    "項目 1": 50,
    "項目 2": "さらに追加",
    "項目 3": "abc"
  }
]
hankei6kmhankei6km

とりあえず

これで試してみようと思っていた部分は網羅できたかなと。

ここまでの感想としては「とにかくお手軽で使いやすい」となる。

あとは予想外(予想以上)だった部分について。

Google ドライブ上のすべてのスプレッドシートへのアクセス権は要求されない

これは利用開始のときにも書いた通りで「スプレッドシート単位の共有」でサービスが実現されている。

スプレッドシート更新にあわせて API がビルドされる

試してみる前は「API 実行時に SSSAPI が毎回スプレッドシートを読みに行く」ような構成だと思っていた(いわゆるサーバーレスファンクション的な挙動)。

実際の挙動としては API をビルドすることで「その時点のスプレッドシートを読み込み API のステートとする」という構成だった(Azure の Durable Functions のような感じ?)。

これについては「スプレッドシートの更新にあわせて他のサービスでの処理をキック」したいような場合、SSAPI のビルドが完了したかわかりにくいというのがある。

追記: 他サービスとの連携について SSSAPI 運営の方から補足いただきました[1]

しかし、更新の少ないマスターデータ的な使い方であればパフォーマンス的にはこちらの方が有利だと予想できる(紹介記事などを見ると実際に速いという結果が出ているらしい)。

また(利用プランにもよるが) Build log には以前のステート(スプレッドシートの内容)が残っていることから履歴を確認することもできる。

クエリーパラメーターでビルドの世代などを指定できると面白いのではとおもった(まぁ具体的な使い方は思いつかなかったのですが毎日更新されるフォームの履歴などに利用できそうかなと)。

追記: 履歴の取得について SSSAPI 運営の方から補足いただきました[2]

脚注
  1. API ビルドの状況については、Wehbook機能によるビルド状態の通知や GitHub Actions などとの連携が予定されているそうです。この辺が実装されるとシステム間での連携がやりやすくなると思われます。 ↩︎

  2. 履歴についてもクエリーパラメーターによる履歴指定の取得は予定されているそうです。 ↩︎

hankei6kmhankei6km

追加

共有を解除してみる

自動更新を ON にした状態で試している。

Build log には反応なし。 API のレスポンスも変化しない。

スプレッドシートを更新しても API のレスポンスは変化しない。

スプレッドシートを更新した状態のスクリーンショット
行を削除してある

この状態で手動アップデートを行うと「権限がありません。共有設定を確認してください。」エラーになる(通知のメールも届く)。

これでも API レスポンスは変化しない。

Build log にエラーが表示されているスクリーンショット

API レスポンス
$  curl -s -H 'Authorization: token XXXXXXXXXX' \
     https://api.sssapi.app/XXXXXXXXX | jq
[
  {
    "項目 1": 10,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 40,
    "項目 2": "これは追加",
    "項目 3": "abc"
  },
  {
    "項目 1": 20,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 30,
    "項目 2": "ここを更新",
    "項目 3": "abc"
  },
  {
    "項目 1": 50,
    "項目 2": "さらに追加",
    "項目 3": "abc"
  }
]
hankei6kmhankei6km

再度共有する

スプレッドシートの共有設定に再度エージェントのユーザーを追加する。

これで retry をクリックすると(しなくてもよいのかも)、API がビルドされてレスポンスが最新の状態になる。

hankei6kmhankei6km

スプレッドシートを移動してみる

Google ドライブ上でスプレッドシートを別フォルダーへ移動。

Build log には反応なし。API レスポンスも変化しない。

移動した状態で変更すれば API がビルドされレスポンスも変化する。

スプレッドシートを削除してみる

Google ドライブ上でスプレッドシートを削除(ゴミ箱へ移動)。

Build log には反応なし。API レスポンスも変化しない。

「retry」も成功する。共有しているとゴミ箱にあっても投稿者はコピーを作成できると同じ理屈と思われる。

hankei6kmhankei6km

追加

API ビルド中に fetch してみる

API Optionsの自動更新を OFF にする。

API Optionsの自動更新を OFF にしたスクリーンショット
自動更新を OFF

スプレッドシートを更新する。

更新前のスプレッドシートのスクリーンショット
更新前

更新後のスプレッドシートのスクリーンショット
更新後

fetch スクリプト。

test.sh
#!/bin/bash

set -e

function fetch_api {
  printf "%03d start\n" "${1}"
  curl -s -H 'Authorization: token XXXXXXXX' \
    'https://api.sssapi.app/XXXXXXX' | jq > "tmp/$(printf '%03d' "${1}").json" &
  printf "%03d end\n" "${1}"
}

STEP=10
for ((j = 0; j < 20; j++)); do
  for ((i = 0; i < STEP; i++)); do
    fetch_api "$((j * STEP + i))" &
  done
  sleep ".1"
done

Update を実行しながらスクリプトも実行。

API の設定画面の「Update」ボタンが表示されているスクリーンショット
Update をクリック

スクリプトはエラーにならずに終了。

途中からレスポンスも更新後の内容に変化している。

最初と最後のレスポンス。

$ ls tmp/*.json | wc -l
200
$ cat tmp/000.json
[
  {
    "項目 1": 10,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 20,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 30,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  }
]
$ cat tmp/199.json
[
  {
    "項目 1": 10,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 20,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 30,
    "項目 2": "あいうえお",
    "項目 3": "abc"
  },
  {
    "項目 1": 40,
    "項目 2": "追加",
    "項目 3": "abc"
  }
]
実行時の表示
$ bash test.sh
000 start
001 start
000 end
001 end
004 start
004 end
003 start
002 start
002 end
003 end
005 start
005 end
008 start
008 end
009 start
009 end
007 start
007 end
006 start
006 end
010 start
016 start
014 start
015 start
013 start
018 start
019 start
017 start
011 start
010 end
016 end
014 end
013 end
015 end
018 end
017 end
011 end
019 end
012 start
012 end
020 start
021 start
021 end
022 start
023 start
023 end
026 start
024 start
024 end
026 end
027 start
028 start
020 end
029 start
025 start
025 end
022 end
028 end
027 end
029 end
030 start
030 end
031 start
032 start
033 start
034 start
031 end
033 end
034 end
032 end
036 start
037 start
037 end
036 end
039 start
038 start
038 end
039 end
035 start
035 end
046 start
046 end
040 start
040 end
041 start
041 end
042 start
042 end
043 start
043 end
045 start
047 start
049 start
044 start
049 end
048 start
047 end
045 end
048 end
044 end
057 start
057 end
058 start
058 end
050 start
056 start
051 start
053 start
054 start
059 start
055 start
052 start
053 end
056 end
054 end
059 end
051 end
050 end
055 end
052 end
067 start
067 end
060 start
061 start
061 end
062 start
062 end
063 start
063 end
064 start
064 end
065 start
065 end
066 start
066 end
069 start
068 start
069 end
068 end
060 end
070 start
070 end
072 start
072 end
073 start
074 start
075 start
076 start
077 start
078 start
079 start
071 start
077 end
078 end
076 end
071 end
074 end
075 end
079 end
073 end
087 start
087 end
088 start
088 end
089 start
081 start
081 end
089 end
080 start
083 start
084 start
084 end
085 start
085 end
086 start
083 end
080 end
086 end
090 start
091 start
092 start
095 start
096 start
097 start
098 start
099 start
093 start
094 start
090 end
082 start
091 end
092 end
095 end
096 end
097 end
098 end
099 end
093 end
094 end
082 end
100 start
101 start
101 end
102 start
103 start
103 end
105 start
105 end
107 start
108 start
108 end
104 start
104 end
106 start
106 end
109 start
109 end
102 end
100 end
107 end
118 start
118 end
119 start
119 end
110 start
111 start
112 start
113 start
114 start
115 start
116 start
117 start
117 end
114 end
116 end
112 end
115 end
111 end
113 end
110 end
129 start
129 end
120 start
120 end
122 start
123 start
124 start
125 start
125 end
126 start
127 start
127 end
128 start
128 end
121 start
122 end
124 end
123 end
126 end
130 start
131 start
132 start
132 end
133 start
133 end
136 start
136 end
138 start
138 end
139 start
139 end
135 start
135 end
137 start
137 end
134 start
134 end
130 end
131 end
140 start
140 end
141 start
141 end
144 start
143 start
143 end
148 start
148 end
145 start
145 end
144 end
121 end
142 start
142 end
146 start
146 end
147 start
149 start
147 end
149 end
151 start
151 end
152 start
152 end
153 start
153 end
154 start
154 end
155 start
155 end
156 start
156 end
157 start
157 end
158 start
158 end
159 start
150 start
150 end
159 end
160 start
160 end
161 start
161 end
162 start
162 end
163 start
163 end
164 start
164 end
165 start
165 end
166 start
167 start
167 end
168 start
168 end
169 start
169 end
166 end
173 start
173 end
171 start
172 start
174 start
174 end
177 start
176 start
170 start
176 end
178 start
178 end
179 start
179 end
175 start
177 end
170 end
172 end
171 end
175 end
180 start
181 start
181 end
182 start
182 end
183 start
183 end
185 start
185 end
186 start
186 end
187 start
187 end
188 start
188 end
189 start
189 end
184 start
184 end
180 end
198 start
198 end
199 start
190 start
191 start
192 start
193 start
194 start
195 start
196 start
197 start
199 end
190 end
191 end
193 end
194 end
196 end
192 end
197 end
195 end
hankei6kmhankei6km

API のレスポンスが変化する Option

Option を変更した後に手動で Update を実行する必要がある。

hankei6kmhankei6km

Headless CMS 風に使う(nuxt-content + remote-cms-content)

remote-cms-content に SSSAPI 用のクライアントを追加した。

以下のようにスプレッドシートにコンテンツを入力する。

sliug、タイトル、本文などスプレッドシートに複数件入力しているスクリーンショット
コンテンツを入力

以下のマッピング情報を記述。

mapconfig.yaml
passthruUnmapped: true

flds:
  - query: slug
    dstName: id
    fldType: id

  - query: タイトル
    dstName: title
    fldType: string

  - query: 本文
    dstName: content
    fldType: string

  - query: カテゴリー
    dstName: category
    fldType: string

.env とコマンドの実行例

.env
RCC_CLIENT_KIND=sssapi
RCC_API_BASE_URL=https://api.sssapi.app/
RCC_CREDENTIAL__0=<ACCESS TOKEN>
RCC_MAP_CONFIG=scripts/mapconfig.yaml
API_NAME=<API PATH>
rcc --static-root static/ save --page-size 100 "${API_NAME}" content static/images

スクリプトにして実行。

$ npm run save:content

> rcc@1.0.0 save:content
> bash scripts/save_content.sh

saveRemoteContent: start max-repeat=10
ClientBase.fetch: start
ClientBase.fetch: skip=0, pageSize=100
ClientBase.fetch:   count=3
saveRemoteContent: repeat=1 done
ClientBase.fetch: done
saveRemoteContent: done

$ tree content/
content/
├── index.md
├── samples.md
└── usage.md

0 directories, 3 files

Front Matter 付きの Markdwon ファイルが出来上がる。

usage.md
---
_RowNumber: -1
id: usage
createdAt: 2022-01-13T08:27:27.947Z
updatedAt: 2022-01-13T08:27:27.947Z
title: 使い方
category: 使い方
position: 2
---
なにか使い方的なことを書く。

## 基本的なコマンド

- `save` - コンテンツを保存
- `watch` - 指定されたコンテンツを監視し変更があれば保存

これで nuxt-content で利用しやすくなった。

hankei6kmhankei6km

AppSheet

上記のスプレッドシートを AppSheet のアプリにした。

既に AppSheet を使っているのでスプレッドシートの「拡張機能」メニューから AppSheet を選択するとアプリにできる。

スプレッドシートの「拡張機能」を開いて「アプリを作成」を選択しているスクリーンショット
「アプリを作成」を選択

AppSheet のデザイナー画面でカラムなど調整すると以下のように編集フォームが使えるようになる。
AppSheet で記事を編集しているスクリーンショット
記事の編集

Save するとスプレッドシートも更新される。
AppSheet での更新が反映されたスプレッドシートのスクリーンショット
更新が反映されている

この状態で SSSAPI の API を fetch する(Headless CMS 風で使ったスクリプトを利用)と AppSheet で入力した内容(Markdown)が保存される。

test1.md
---
_RowNumber: -1
id: test1
createdAt: 2022-01-13T09:00:32.258Z
updatedAt: 2022-01-13T09:00:32.258Z
title: テストの記事
category: その他
position: 4
---
AppSheet の設定を行ったので少し編集。

なんだかんだいっても入力フォームがある方が楽といえば楽である。

あとは AppSheet ではオートセーブではなく明示的なセーブなのでスプレッドシートの更新回数が削減できるというメリットもある。

問題は、API のビルドが終了したタイミングがわからないことかな。
hankei6kmhankei6km

フォルダーを共有した場合

スプレッドシートではなくフォルダーを共有するとどうなるか?

スプレッドシートを共有した場合と同じように扱えた。

また共有しているフォルダー内のスプレッドシートから API の作成も可能だった。

が、ドキュメントには明記されてないようなので使わない方が無難かな。

追記: SSSAPI 運営の方から補足いただきました。

フォルダーの共有でも問題ないそうです。

このスクラップは2022/01/15にクローズされました