見出し画像

Bubble解体新書 ~Data APIを使ってBubble上のデータを取得する~

はじめに

Bubbleは基本的なCRUDを伴ったWebサービスの効率的な構築だけではなく、API Workflowを組み合わせることによるバッチ処理やフロントエンドの負荷軽減等、ノーコードツールの中でも比較的柔軟な実装が可能になっています。
しかし、それでもノーコードで複雑なロジックを含んだ処理を表現するのは苦手です。例えば、Bubbleを使用している弊社のマッチングアプリTeeeではユーザーの要望に応じた複雑なマッチング処理を行なっています。

teee.me/lp

このような複雑な処理を無理にBubbleで記述するのではなく、Data APIを介して外部のシステムと組み合わせることで、より柔軟で効率的な事業開発が可能になります。
(TeeeではBubbleとGCP上に構築したシステムを組み合わせて開発しています。)

本記事ではData APIを用いてデータを検索する手順を解説します。
Data APIについては公式のドキュメントでも解説があるので、併せてご確認ください。

前提知識

  • Bubbleの基本的な操作方法

  • Web APIに関する基礎的な知識

この記事のゴール

  • Bubble Data APIでBubble上のデータを取得する方法が分かる

  • Goを使ってBubble Data APIを使用する方法が分かる

※ Data APIを利用するためにはPersonal以上のプランが必要です。
(無料トライアルがあるので興味がある方は是非触ってみてください!)

ダミーデータの作成

以下のようにUser型を定義し、ダミーデータを数件作成しました。
今回はBubble Data APIを使用してこれらのデータを取得する手順を紹介します。

User型定義
Userダミーデータ

設定

まずはAPIでデータが取得できるようにアプリの設定を変更する必要があります。
Setting → API の Enable Data API にチェックを入れると、Data APIのエンドポイントが表示されます。

データ型のPrivacy設定も確認しておきましょう。
今回は以下のように設定しました。

便宜上、View all fields にチェックを入れることでUser型の全てのフィールドをAPIで公開していますが、フィールドごとにプライバシー設定が可能です。

データの取得

Data APIを使用してデータを取得する方法は大きく以下の2つあります。

  • unique idを用いたデータの取得

  • データのリストを検索して取得

unique idによるデータの取得

unique idが事前に分かっている場合は以下のようなエンドポイントでデータの取得が可能です。

GET https://appname.bubbleapps.io/api/1.1/obj/typename/unique_id

Postman を使ってAPIを叩いてみます。

JSON形式でBubble上のデータを取得することができました。
レスポンスのデータ構造については後ほど解説します。

データのリストを検索して取得

リストの検索では、クエリパラメータを使用して柔軟な検索が可能です。
使用可能なパラメータは大きく分けて以下の3種類があります。

  • ページネーション(limit, cursor

  • ソート(sort_field, descending

  • 検索条件(constraints

検索条件(constraints)について
検索条件の作成方法が少し複雑なので詳しく解説します。
constraintsパラメータには検索条件のJSON配列をURLエンコードした値が入ります。
検索条件とは、key, constraint_type, valueが入ったオブジェクトのことです。
それぞれ簡単にまとめます。

key:
 検索条件を適用するフィールド名。
 _all を指定すると全文検索することができる。
 _id (unique idのこと) をkeyとして使ってはならない。

constraint_type:
 適用する検索条件の型。以下の8種類がある。
 - equals, not equals
 - is_empty, is_not_empty
 - text contains, not text contains
 - greater than, less than
 - in, not in
 - contains, not contains
 - empty, not empty
 - geographic_search

value:
 比較する値。
 constraint_typeによってはvalueが入らないものもある。

例えば、「年齢が25より大きく、趣味に筋トレを含む」という条件は以下のようになります。

[

	{
		"key": "Age",
		"constraint_type": "greater than",
		"value": 25
	},
	{
		"key": "Hobbys",
		"constraint_type": "contains",
		"value": "筋トレ"
	}
]

レスポンスの形式

unique idを指定して取得した場合と、リストを取得した場合でレスポンスの形式が少し異なっているのでそれぞれ解説します。

unique idを指定した場合

unique idを指定して取得した場合のレスポンスをもう一度見てみましょう。

{
    "response": {
        "_id": "1674564837842x154031005649724930",
        "user_signed_up": true,
        "Created Date": "2023-01-24T12:53:57.842Z",
        "Modified Date": "2023-01-27T04:08:42.559Z",
        "authentication": {
            "email": {
                "email": "soutaro39@example.net",
                "email_confirmed": null
            }
        },
        "Hobbys": [
            "サウナ",
            "筋トレ"
        ],
        "Age": 30,
        "Name": "そうたろう"
    }
}

responseに指定したUserのデータが入っていることが分かります。
データのキーはデフォルトでBubble上のフィールド名になります。

authenticationについて
authentication
にはUserの認証情報が入ります。デフォルトではemailのみですが、OAuthを用いて外部サービスのアカウントによる認証を実装した場合、それらの認証情報も取得することができます。
また、emailはBubbleのエディタ上ではUser直下にあるのですが、Data APIで取得する場合は上記のようにauthenticationの中にあるので注意が必要です。

リストの取得

以下はUserのリストを条件を付けずに全件取得したレスポンスです。

{
    "response": {
        "cursor": 0,
        "results": [
            {
                "user_signed_up": true,
                "Created Date": "2023-01-24T12:53:57.842Z",
                "Modified Date": "2023-01-27T04:08:42.559Z",
                "authentication": {
                    "email": {
                        "email": "soutaro39@example.net",
                        "email_confirmed": null
                    }
                },
                "Hobbys": [
                    "サウナ",
                    "筋トレ"
                ],
                "Age": 30,
                "Name": "そうたろう",
                "_id": "1674564837842x154031005649724930"
            },
            {
                "user_signed_up": true,
                "Created Date": "2023-01-25T08:08:33.286Z",
                "Modified Date": "2023-01-27T04:08:50.539Z",
                "authentication": {
                    "email": {
                        "email": "yamada.nanami@example.net",
                        "email_confirmed": null
                    }
                },
                "Hobbys": [
                    "旅行",
                    "筋トレ"
                ],
                "Age": 20,
                "Name": "ななみ",
                "_id": "1674634113286x681137982272706800"
            },
            {
                "user_signed_up": true,
                "Created Date": "2023-01-25T08:57:05.470Z",
                "Modified Date": "2023-01-27T04:08:58.856Z",
                "authentication": {
                    "email": {
                        "email": "kobayashi.akemi@example.org",
                        "email_confirmed": null
                    }
                },
                "Hobbys": [
                    "スポーツ観戦",
                    "映画鑑賞",
                    "旅行"
                ],
                "Age": 40,
                "Name": "あけみ",
                "_id": "1674637025470x706808802805861500"
            },
            {
                "user_signed_up": true,
                "Created Date": "2023-01-25T08:59:18.502Z",
                "Modified Date": "2023-01-27T04:09:06.488Z",
                "authentication": {
                    "email": {
                        "email": "taro.kiriyama@example.org",
                        "email_confirmed": null
                    }
                },
                "Hobbys": [
                    "サウナ",
                    "旅行"
                ],
                "Age": 25,
                "Name": "たろう",
                "_id": "1674637158502x754696439846911400"
            },
            {
                "user_signed_up": true,
                "Created Date": "2023-01-25T09:00:04.144Z",
                "Modified Date": "2023-01-27T04:09:12.599Z",
                "authentication": {
                    "email": {
                        "email": "tomoya.sugiyama@example.com",
                        "email_confirmed": null
                    }
                },
                "Hobbys": [
                    "筋トレ",
                    "スポーツ観戦"
                ],
                "Age": 35,
                "Name": "ともや",
                "_id": "1674637204144x801730942584853100"
            }
        ],
        "count": 5,
        "remaining": 0
    }
}

先ほどはresponseに直接ユーザーのデータが入っていたのに対して、
cursor
, results, count, remaining の4つのデータが返却されていることが分かります。

cursor: 取得したデータの最初が全体の何番目なのか。0から始まる
results: 取得したデータのリスト
count: 取得したデータの数
remaining: 残りのデータの数

manual.bubble.io

リストの取得は一度に最大100件しか取得することができません。
100件より多くのデータを扱う場合はこれらのページネーションに関する値を上手く使って取得しましょう。

Goでリクエストの送信

ここまでの内容を踏まえて、実際にGoを使ってBubble Data APIを実行して、Bubble上のUserデータを取得するコードを紹介します。
以下は、「年齢が25歳より大きく、趣味に筋トレを含むUser」をAPIを用いて検索するコードです。

実行結果

$ go run main.go
{Name:そうたろう Age:30 Hobbys:[サウナ 筋トレ] Authentication:{Email:{Email:soutaro39@example.net}}}
{Name:ともや Age:35 Hobbys:[筋トレ スポーツ観戦] Authentication:{Email:{Email:tomoya.sugiyama@example.com}}}

補足1: レスポンスのキーの命名について

Setting → API のUse field display instead of ID for key names のチェックを外すとキーの命名が以下のようにフィールド名 + 型名に変更されます。

{
    "response": {
        "_id": "1674564837842x154031005649724930",
        "user_signed_up": true,
        "Created Date": "2023-01-24T12:53:57.842Z",
        "Modified Date": "2023-01-27T04:08:42.559Z",
        "authentication": {
            "email": {
                "email": "soutaro39@example.net",
                "email_confirmed": null
            }
        },
        "hobby_list_option_hobby": [
            "サウナ",
            "筋トレ"
        ],
        "phonenumber_number": 30,
        "name_text": "そうたろう"
    }
}

Bubbleの仕様上、同じ名前で複数フィールドを作成することが可能になっています。
チェックを入れている状態だとそのうちの1つしか取得できないのに対し、チェックを入れていない状態だとキー名がコンフリクトしないように命名されるので全てのフィールドを取得することができます。
基本はチェックを入れている状態で問題ないと思いますが、ユースケースによって使い分けてみてください。

補足2: プライバシー設定で非公開になっているデータの取得方法

設定の項目では以下のような説明をしました。

便宜上、View all fields にチェックを入れることでUser型の全てのフィールドをAPIで公開していますが、フィールドごとにプライバシー設定が可能です。

しかし、「外部に公開したくないけど、Data APIで取得したい」という場合もあると思います。
実は、認証トークンをリクエストヘッダに付与することでプライバシールールを無視して全てのデータを取得することが可能になっています。
認証トークンはSetting→APIからGenerate a new API tokenボタンを押すことで生成できます。

以下のように、全てのフィールドのpermissionを外しても認証トークンを付与してリクエストすることで全てのデータが取得できていることが分かります。

Userのprivacy設定

Goでリクエストの際にヘッダーにトークンを付与する場合は、以下のようなコードになります。

req, err := http.NewRequest(http.MethodGet, u.String(), nil)
if err != nil {
	return nil, err
}

apiToken := "7cd2e7907996b2c7526affa290955c2c"
req.Header.Add("Authorization", "Bearer "+apiToken)

res, err := http.DefaultClient.Do(req)

※ 今回はソースコードにトークンをベタ書きしていますが、トークンは流出を防ぐため、環境変数で管理するのが一般的です。

最後に

今回は解説しきれなかったのですが、Data APIを使ったデータの作成、編集も可能になっています。

Data APIを活用して、Bubbleを利用したWebシステムのバリエーションが多くなることで、
「定形業務の効率化やプロトタイプ開発には向いているが、プロダクトの本番開発には向かない」
というノーコードの認知を変える一助になれば幸いです。


最後になりましたが、弊社は今回ご紹介したBubbleを利用してWebサービスの受託開発を行っています。Bubbleはカスタマイズ性が高く開発期間を短縮することができますが、本格的なWebサービスを構築するには一定以上のノウハウが必要になります。

今後もBubbleの記事を掲載しノウハウの一端を公開していく予定ですが、弊社に任せていただければこのBubbleを利用して最適なサービスを短期間で開発することができると自負しておりますので、興味のある方はぜひお気軽にお声がけください!
(合同会社tempのお問い合わせ先)
https://llctemp.me/contact


この記事が気に入ったらサポートをしてみませんか?