SNS「Bluesky」へ「ASTERIA Warp」からノーコードで投稿する方法～フローの内容とつまづきポイントの全解説～

最近、SNS「Bluesky」が人気急上昇中ですね！
招待制ではなくなったので、一気に登録者が増えているようです。

そんなBlueskyへ、ノーコードのデータ連携ツール「[ASTERIA Warp](https://www.asteria.com/jp/warp/)」から投稿するフローを作成してみました！
この記事では、そのフローの内容や作成中につまずいた点を解説したいと思います。

（ご注意：ASTERIA Warpの基本的な使い方をご存じのかた向けに書かれています:pray:）

なお、ASTERIA Warp 2312で試しています。JSONストリームを使用していますので、ASTERIA Warp 2212以降のバージョンが必要です。

# 投稿した内容
システムを初めて動かすときのお決まりの言葉といえばHello world!ですね。
ここではこんな[投稿](https://bsky.app/profile/shozzy-bsky.bsky.social/post/3klltnjp4nk2g)をしてみました。
固定文言+投稿日時という内容です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/77b1c8b9-66b9-aeed-158f-141d41deeb23.png)


# APIの仕様を把握する
フロー作成の前に、まずはBlueskyのAPI仕様を把握する必要があります。
[公式サイト](https://www.docs.bsky.app/docs/get-started "Bluesky Developer APIs")で確認しましょう。

公式サイトにはTypeScript/CURL/Pythonでのサンプルコードが掲載されていますが、ここではCURLでの接続方法を参考にします。これは、TypeScriptやPythonのサンプルコードは専用クライアントをインストールする前提になっているのに対し、CURLでは専用クライアント無しでAPIを呼び出す方法が書かれているためです。ASTERIA Warpから接続するときは「RESTコンポーネント」を使ってAPIを呼び出しますので、専用クライアント無しでの接続方法を把握する必要があります。

## 把握したこと
- 処理の流れ
    - 最初にセッションを作成し、アクセストークンを入手する（Create a session）
    - そのアクセストークンを使って、投稿を実施する（Create a post）
- 入力が必要な情報
    - ハンドル（ユーザーID）
    - パスワード
    - （セッション作成時に入手した）アクセストークン
- 各APIのエンドポイント
    - セッション作成 `https://bsky.social/xrpc/com.atproto.server.createSession`
    - 投稿 `https://bsky.social/xrpc/com.atproto.repo.createRecord`
- 各APIのリクエストとレスポンスのJSONデータ構造（詳細はここでは省略します）

これらの情報を元に、フロー作成をはじめましょう！

# フロー作成
## 先に完成品をお見せします
セッション作成フロー「CreateSession」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/623673c6-a1e3-0509-f020-de47f91cdaf9.png)

投稿フロー「CreatePost」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/d6fe25e7-dbb8-a100-aa8c-759ee858b047.png)

とてもシンプルなフローにできました:tada:

※注：このフローでは、アクセストークンが期限切れになったときリフレッシュトークンを用いて再取得する処理は考慮していません。

## 準備
ハンドル、パスワード、アクセストークンは「外部変数セット」に保存しておくことにします。
これは、秘密にすべき情報をフローの中に直接書き込むことを避けるためと、同じ情報を複数の箇所に重複保管しないために選択しました。

ここでは外部変数セット「BlueskySocial」を、以下の内容で作成しました。
![スクリーンショット 2024-02-17 151951.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/18335d55-7f61-97f5-4ca8-1a7c1313d91b.png)

- 定数
    - BLUESKY_HANDLE
        - 初期値(上記画像ではyour_idと書いてある場所)にハンドル（ユーザーID）を入れておきます
        - 私の場合ですと `shozzy-bsky.bsky.social` を設定しました。
            - ブラウザでログインするときは `shozzy-bsky` だけで良いのですが、ここでは省略なしで書く必要がありました（:bomb:つまづいたポイント1つめ）
    - BLUESKY_PASSWORD
        - 初期値(上記画像ではyour_passwordと書いてある場所)にパスワードを入れておきます
- アプリケーション変数
    - accessJWT
        - アクセストークン保存用
    - refreshJWT
        - リフレッシュトークン保存用（今回は使っていませんが、保存だけしてあります）

## プロジェクト作成
プロジェクト名「BlueskySocial」で作成しました。

## セッション作成フロー
フロー名「CreateSession」で作成しました。

### 全体の流れ（再掲）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/9f4a8b7f-7ad7-8307-c826-bacb0f9de71a.png)

### 設定のポイント
デフォルトから変更した箇所を解説します。

- 外部変数セット「BlueskySocial」を貼り付け
- 1つめのMapperコンポーネント
    - 出力ストリーム `JSON`
      ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/9d3b608d-3404-cc17-afb0-a2a61383cd34.png)
    - マッピング内容
      ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/144e0079-9f07-2e10-2f06-4847b5209f4a.png)
      - このマッピングで、API仕様の通りにハンドル(ユーザーID)とパスワードが書かれたJSONデータを用意しています
- RESTコンポーネント
    - 出力ストリーム `JSON`
      ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/2943439b-6774-8fc1-c590-e17cec032eaa.png)
    - コネクションを使用 `いいえ`
    - URL `https://bsky.social/xrpc/com.atproto.server.createSession`
    - HTTPメソッド `POST`
:::note info
ヒント：
これだけの項目数を手入力するのは大変すぎますので、ストリームの項目定義をインポートすると便利です。
以下のような方法でインポート可能です。
・RESTのテスト実行機能で入手したJSONを「フィールド定義のインポート」で取り込む
・一度ストリームの項目設定をしない状態でフローを動作させて入手したJSONデータをローカルファイルに保存しておき、ストリームの右クリックメニューから「インポート」して取り込む
:::

- 2つめのMapperコンポーネント
    - 入力をそのまま出力 `はい`
    - マッピング内容
      ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/ac7d4f1c-0268-40df-8cec-97ae6d44d706.png)
        - このマッピングで、アプリケーション変数にアクセストークンなどを保存しています
        - アプリケーション変数に保存したデータは永続化されますので、保存された値を他のフローで利用することができます


これでセッション作成フローは完成です！


## 投稿フロー
フロー名「CreatePost」で作成しました。

### 全体の流れ（再掲）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/3f32cca8-aca2-a942-887f-57794182f0bb.png)

### 設定のポイント
先ほどと同様に、デフォルトから変更した箇所の解説です。

- 外部変数セット「BlueskySocial」を貼り付け
- Mapperコンポーネント
    - 出力ストリーム `JSON`
      ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/dc600985-0ee2-adc2-0a4e-3f9b0e4750cc.png)
    - マッピング内容
      ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/27e53b0d-8eba-02a2-b2f7-fc5a4a2538fb.png)
    - マッパー関数の詳細
        - 上のConst関数
            - データ `app.bsky.feed.post`
        - 下のConst関数
            - データ `はろー青空わーるど！`
        - Now関数
            - 日付フォーマット `yyyy-MM-dd'T'HH:mm:ss'Z'`
            - タイムゾーン `(GMT)`
                - API仕様で、UTCでの投稿日時をISO8601形式で設定する必要があるため、この設定が必要です
                - 日付フォーマットは上記テキストを直接入力してください。プルダウンではこの選択肢は出てきません
                - ここが:bomb:つまづいたポイント2つめでした。TとZをシングルクオートで括る必要があることに気付くまで、少し時間がかかりました...

        - Concat関数
            - 区切り文字 `\n`
            - 区切り文字にメタ文字を使用 `はい`
            - 入力順
              ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/adbf5045-2ee0-96d5-dcff-b3d0a0e0f36c.png)

- RESTコンポーネント
    - 出力ストリーム `JSON`
      ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120785/e58d3154-6fb8-1fb2-63bd-03e9a83af3bb.png)
    - コネクションを使用 `いいえ`
    - URL `https://bsky.social/xrpc/com.atproto.repo.createRecord`
    - HTTPメソッド `POST`
    - 送信ヘッダー（以下の1行を追加）
        - ヘッダー名 `Authorization`
        - 値 `Bearer ${exvar.BlueskySocial.accessJWT}`
            - 値は、右端の歯車マークをクリックし「プロパティ式」機能を利用して設定してください

これでフロー完成です！！:tada:

あとは、先にセッション作成フローを動かし、続いて投稿フローを動かせば、投稿できます！

# おわりに

少し詰まる点もありましたが、思い立って1時間ほどで完成形にすることができました。
詰まらなければもっと短時間で作成できますね。

100種類以上の様々なデータソースと接続できるASTERIA Warpですから、社内システムと連携して自動投稿botを作成したり、投稿を取得するAPIを利用すれば自分の投稿への反応を抽出したりと、いろいろ応用できそうです！

最後までご覧いただきありがとうございました！

---
[PR] 弊社アステリア株式会社では、居住地不問で一緒に働く仲間を募集しています！新卒採用もしてますよ！
https://www.wantedly.com/companies/asteria/projects