データの保存方法 |
|
---|---|
PUT | 定義されたパスにデータの書き込みや置換を行います(例: fireblog/users/user1/<data> )。 |
PATCH | データのすべてを置換することなく、定義済みのパスのキーの一部を更新します。 |
POST | Firebase データベース内のデータのリストに追加します。POST リクエストを送信するたびに、Firebase クライアントから fireblog/users/<unique-id>/<data> のような一意のキーが生成されます。 |
削除 | 指定した Firebase データベース参照からデータを削除します。 |
PUT によるデータの書き込み
REST API による基本的な書き込み操作は PUT
です。ここでは、データの保存方法を示すために、投稿とユーザーが含まれるブログ アプリケーションを構築します。このアプリケーションのすべてのデータは、Firebase データベースの URL「https://docs-examples.firebaseio.com/fireblog」の「fireblog」のパスに保存されます。
Firebase データベースにいくつかのユーザーデータを保存するところから始めましょう。一意のユーザー名を使用して各ユーザーを保存します。また、ユーザーの氏名と生年月日も保存します。各ユーザーが一意のユーザー名を持ち、これがキーとなって別途作成する必要がないため、ここでは POST
ではなく PUT
を使用するのが適しています。
PUT
を使用すると、文字列、数字、ブール値、配列、または任意の JSON オブジェクトを Firebase データベースに書き込むことができます。次の例では、オブジェクトを渡します。
curl -X PUT -d '{ "alanisawesome": { "name": "Alan Turing", "birthday": "June 23, 1912" } }' 'https://docs-examples.firebaseio.com/fireblog/users.json'
JSON オブジェクトがデータベースに保存されると、オブジェクトのプロパティが子の場所にネスト式に自動マッピングされます。新しく作成されたノードに移動すると、値「Alan Turing」が表示されます。また、データを子の場所に直接保存することもできます。
curl -X PUT -d '"Alan Turing"' \ 'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome/name.json'
curl -X PUT -d '"June 23, 1912"' \ 'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome/birthday.json'
上述の 2 つの例、つまり、値をオブジェクトと同時に書き込む場合と、子の場所に別個に書き込む場合では、結果として同じデータが Firebase データベースに保存されることになります。
{ "users": { "alanisawesome": { "date_of_birth": "June 23, 1912", "full_name": "Alan Turing" } } }
成功したリクエストは 200 OK
HTTP ステータス コードで示されます。レスポンスには、データベースに書き込んだデータが含まれています。最初の例では、データを監視しているクライアントで 1 つのイベントのみがトリガーされますが、2 番目の例では 2 つのイベントがトリガーされます。データがパス users にすでに存在する場合、最初の方法ではデータが上書きされることに注意してください。これに対し、2 番目の方法では、個々の子ノードの値のみが変更され、他の子は変更されません。PUT
は JavaScript SDK の set()
と同義です。
PATCH によるデータの更新
PATCH
リクエストを使用すると、既存のデータを上書きすることなく、特定の場所の特定の子を更新できます。それでは、PATCH
リクエストを使用して Turing のユーザーデータにニックネームを追加してみましょう。
curl -X PATCH -d '{ "nickname": "Alan The Machine" }' \ 'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome.json'
上記のリクエストは、子 name
や birthday
を削除することなく、alanisawesome
オブジェクトに nickname
を追加します。代わりに PUT
リクエストを発行した場合、name
と birthday
はリクエストに含まれないため削除されています。これで、Firebase データベースのデータが次のようになります。
{ "users": { "alanisawesome": { "date_of_birth": "June 23, 1912", "full_name": "Alan Turing", "nickname": "Alan The Machine" } } }
成功したリクエストは 200 OK
HTTP ステータス コードで示されます。応答には、データベースに書き込まれた更新済みデータが含まれています。
Firebase では、マルチパスの更新もサポートされています。つまり、PATCH
では、Firebase データベース内の複数の場所にある値を同時に更新できます。これは、データの非正規化に役立つ強力な機能です。マルチパスの更新を使用すると、Alan と Grace に同時にニックネームを追加できます。
curl -X PATCH -d '{ "alanisawesome/nickname": "Alan The Machine", "gracehopper/nickname": "Amazing Grace" }' \ 'https://docs-examples.firebaseio.com/fireblog/users.json'
この更新後は、Alan と Grace の両方にニックネームが追加されています。
{ "users": { "alanisawesome": { "date_of_birth": "June 23, 1912", "full_name": "Alan Turing", "nickname": "Alan The Machine" }, "gracehop": { "date_of_birth": "December 9, 1906", "full_name": "Grace Hopper", "nickname": "Amazing Grace" } } }
パスを含めてオブジェクトを書き込むことでオブジェクトを更新すると、異なる動作が発生することに注意してください。この方法で Grace と Alan を更新するとどうなるでしょうか。
curl -X PATCH -d '{ "alanisawesome": {"nickname": "Alan The Machine"}, "gracehopper": {"nickname": "Amazing Grace"} }' \ 'https://docs-examples.firebaseio.com/fireblog/users.json'
この結果、異なる動作が発生します。つまり、/fireblog/users
ノード全体が上書きされます。
{ "users": { "alanisawesome": { "nickname": "Alan The Machine" }, "gracehop": { "nickname": "Amazing Grace" } } }
条件付きリクエストによるデータの更新
条件付きリクエスト(REST においてトランザクションに相当)を使用すると、既存の状態に従ってデータを更新することができます。たとえば、upvote カウンタの値を増やす際、複数の upvote が同時に行われた場合にもカウントに正確に反映されるようにするには、条件付きリクエストを使用してカウンタに新しい値を書き込みます。カウンタを同じ値に変更する書き込みが 2 回行われることはなくなり、1 つの書き込みリクエストが失敗して、新しい値でリクエストを再試行できるようになります。- 特定の場所で条件付きリクエストを実行するには、その場所における現在のデータの一意の ID(ETag)を取得します。その場所のデータが変更されると、ETag も変更されます。
PATCH
以外の任意のメソッドを使用して ETag をリクエストできます。次の例では、GET
リクエストを使用しています。curl -i 'https://test.example.com/posts/12345/upvotes.json' -H 'X-Firebase-ETag: true'
ヘッダー内で ETag を具体的に呼び出すと、指定した場所の ETag が HTTP レスポンス内で返されます。HTTP/1.1 200 OK Content-Length: 6 Content-Type: application/json; charset=utf-8 Access-Control-Allow-Origin: * ETag: [ETAG_VALUE] Cache-Control: no-cache 10 // Current value of the data at the specified location
- 返された ETag を次の
PUT
またはDELETE
リクエストに含めて、この ETag 値と具体的に一致するデータを更新します。この例では、カウンタを 11(最初にフェッチした値である 10 よりも 1 大きい値)に更新して、値が一致しない場合にリクエストが失敗するようにするには、次のコードを使用します。curl -iX PUT -d '11' 'https://[PROJECT_ID].firebaseio.com/posts/12345/upvotes.json' -H 'if-match:[ETAG_VALUE]'
指定した場所にあるデータの値が 10 のままであれば、PUT
リクエストの ETag が一致し、リクエストが成功すると、11 がデータベースに書き込まれます。HTTP/1.1 200 OK Content-Length: 6 Content-Type: application/json; charset=utf-8 Access-Control-Allow-Origin: * Cache-Control: no-cache 11 // New value of the data at the specified location, written by the conditional request
別のユーザーがデータベースに新しい値を書き込んだ場合のように、この場所が ETag と一致しなくなっていた場合、リクエストは失敗し、その場所には書き込まれません。返されたレスポンスには、新しい値と ETag が含まれます。HTTP/1.1 412 Precondition Failed Content-Length: 6 Content-Type: application/json; charset=utf-8 Access-Control-Allow-Origin: * ETag: [ETAG_VALUE] Cache-Control: no-cache 12 // New value of the data at the specified location
- リクエストを再試行する場合は、新しい情報を使用します。Realtime Database が、失敗した条件付きリクエストを自動的に再試行することはありません。失敗したレスポンスによって返された情報から新しい値と ETag を取得して、新しい条件付きリクエストを作成することができます。
REST ベースの条件付きリクエストは、HTTP の if-match 標準を実装します。ただし、この標準とは次の点が異なります。
- 各 if-match リクエストで指定できる ETag 値は 1 つのみです。ETag 値を複数指定することはできません。
- 標準ではすべてのリクエストで ETag を返すことを推奨していますが、Realtime Database が ETag を返すのは、
X-Firebase-ETag
ヘッダーを含むリクエストの場合のみです。これにより、標準リクエストの費用が低くなります。
条件付きリクエストは、通常の REST リクエストよりも遅くなる可能性があります。
データのリストの保存
Firebase データベース参照に追加されたすべての子に対してタイムスタンプベースの一意のキーを生成するには、POST
リクエストを送信します。users
パスの場合は、各ユーザーが一意のユーザー名を持っているため、独自のキーを定義するのが合理的でした。一方、ユーザーがブログの投稿をアプリに追加したときは、POST
リクエストを使用して、ブログの投稿ごとにキーを自動生成します。
curl -X POST -d '{ "author": "alanisawesome", "title": "The Turing Machine" }' 'https://docs-examples.firebaseio.com/fireblog/posts.json'
これで、posts
パスには次のデータができます。
{ "posts": { "-JSOpn9ZC54A4P4RoqVa": { "author": "alanisawesome", "title": "The Turing Machine" } } }
200 OK
リクエストを使用したためにキー -JSOpn9ZC54A4P4RoqVa
が自動的に生成されていることに注目してください。成功したリクエストは POST
HTTP ステータス コードで示されます。応答には、追加された新しいデータのキー名が含まれています。
{"name":"-JSOpn9ZC54A4P4RoqVa"}
データの削除
データをデータベースから削除するには、データの削除元にするパスの URL を含んだ DELETE
リクエストを送信します。次のリクエストは、Alan を users
パスから削除します。
curl -X DELETE \ 'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome.json'
成功した DELETE
リクエストは 200 OK
HTTP ステータス コードで示されます。レスポンスには JSON null
が含まれています。
URI パラメータ
REST API は、データベースにデータを書き込むときに次の URI パラメータを受け入れます。
auth
auth
リクエスト パラメータを使用すると、Firebase Realtime Database Security Rules で保護されたデータにアクセスできます。このパラメータはすべての種類のリクエストでサポートされています。引数には、Firebase アプリのシークレットまたは認証トークンを使用できます。これらについては、ユーザーの承認セクションで説明します。次の例では、auth
パラメータを指定して POST
リクエストを送信しています。ここで、CREDENTIAL
は、Firebase アプリのシークレットまたは認証トークンです。
curl -X POST -d '{"Authenticated POST request"}' \ 'https://docs-examples.firebaseio.com/auth-example.json?auth=CREDENTIAL'
プリント
print
パラメータを使用すると、データベースからのレスポンスの形式を指定できます。リクエストに print=pretty
を追加すると、データは人が読める形式で返されます。print=pretty
は、リクエスト GET
、PUT
、POST
、PATCH
、DELETE
でサポートされています。
データを書き込むときにサーバーからの出力を抑制するには、print=silent
をリクエストに追加します。その結果、レスポンスは空になり、リクエストが成功した場合は 204 No Content
HTTP ステータスで示されます。print=silent
は、リクエスト GET
、PUT
、POST
、PATCH
でサポートされています。
サーバー値の書き込み
サーバー値は、プレースホルダ値を使用して特定の場所に書き込むことができます。プレースホルダ値は、単一の ".sv"
キーを持つオブジェクトです。このキーの値は、設定するサーバー値の種類です。たとえば、ユーザーが作成されたときにタイムスタンプを設定するには、次を実行します。
curl -X PUT -d '{".sv": "timestamp"}' \ 'https://docs-examples.firebaseio.com/alanisawesome/createdAt.json'
"timestamp"
はサポートされている唯一のサーバー値で、UNIX エポック時刻からの経過時間です(ミリ秒単位)。
書き込みパフォーマンスの改善
大量のデータをデータベースに書き込む場合は、print=silent
パラメータを使用して、書き込みパフォーマンスを改善しつつ、帯域幅の使用量を減らすことができます。通常の書き込み動作では、サーバーは、書き込まれた JSON データで応答します。print=silent
が指定された場合、サーバーは、データが受信されると直ちに接続を閉じて帯域幅の使用量を減らします。
データベースに対する大量のリクエストを行う場合は、HTTP ヘッダーで Keep-Alive
リクエストを送信することで HTTPS 接続を再利用できます。
エラー条件
REST API は、次の状況でエラーコードを返します。
HTTP ステータス コード | |
---|---|
400 Bad Request(不正なリクエスト) |
次のいずれかのエラー条件:
|
401 Unauthorized(未承認) |
次のいずれかのエラー条件:
|
404 Not Found(未検出) | 指定された Firebase データベースが見つからない。 |
500 Internal Server Error(内部サーバーエラー) | サーバーがエラーを返した。詳細については、エラー メッセージをご覧ください。 |
503 Service Unavailable(サービス利用不可) | 指定された Firebase Realtime Database が一時的に使用できない。この場合、リクエストは試行されていません。 |
データのセキュリティ保護
Firebase には、データのさまざまなノードへの読み取りと書き込みのアクセス権を持つユーザーを定義できるセキュリティ言語が備わっています。詳しくは、Realtime Database Security Rules をご覧ください。
これで、データの保存についての説明は終了です。次のセクションでは、REST API を使用して Firebase データベースからデータを取得する方法について説明します。