Reading Data with GET
We can read data from our Firebase database by issuing a GET
request to its URL
endpoint. Let's continue with our blog example from the previous section and read all of our
blog post data:
curl 'https://docs-examples.firebaseio.com/fireblog/posts.json?print=pretty'
A successful request will be indicated by a 200 OK
HTTP status code, and the
response will contain the data we're retrieving.
Adding URI Parameters
The REST API accepts several query parameters when reading data from our Firebase database. Listed below are the most commonly used parameters. For a full list, refer to the REST API Reference.
auth
The auth
request parameter allows access to data protected by
Firebase Realtime Database Security Rules, and is
supported by all request types. The argument can either be your Firebase app's secret or an
authentication token, as described in the Users in Firebase Projects. In the following example we send a GET
request with an auth
parameter, where CREDENTIAL
is either your Firebase app's secret or an
authentication token:
curl 'https://docs-examples.firebaseio.com/auth-example.json?auth=CREDENTIAL'
Specifying print=pretty
returns the data in a human-readable format.
curl 'https://docs-examples.firebaseio.com/fireblog/posts.json?print=pretty'
Specifying print=silent
returns a 204 No Content
on success.
curl 'https://docs-examples.firebaseio.com/fireblog/posts.json?print=silent'
callback
To make REST calls from a web browser across domains you can use
JSONP to wrap the response in a JavaScript
callback function. Add callback=
to have the REST API wrap the returned data in the
callback function you specify. For example:
<script> function gotData(data) { console.log(data); } </script> <script src="https://docs-examples.firebaseio.com/fireblog/posts.json?callback=gotData">
shallow
This is an advanced feature, designed to help you work with large datasets without needing to
download everything. To use it, add shallow=true
as a parameter. This will limit
the depth of the data returned. If the data at the location is a JSON primitive (string, number,
or boolean) its value will simply be returned. If the data snapshot at the location is a JSON
object, the values for each key will be truncated to true. For example, using
the data below:
{ "message": { "user": { "name": "Chris" }, "body": "Hello!" } } // A request to /message.json?shallow=true // would return the following: { "user": true, "body": true } // A request to /message/body.json?shallow=true // would simply return: "Hello!"
Try it out with this curl
request:
curl 'https://docs-examples.firebaseio.com/rest/retrieving-data.json?shallow=true&print=pretty'
timeout
Use this to limit how long the read takes on the server side. If a read request doesn't finish within the allotted time, it terminates with an HTTP 400 error. This is particularly useful when you expect a small data transfer and don't want to wait too long to fetch a potentially huge subtree. Actual read time might vary based on data size and caching.
Specify timeouts
using the following format: 3ms
,
3s
, or 3min
, with a number and a unit. If not
specified, the maximum timeout
of 15min
will be
applied. If the timeout
is not positive, or exceeds the maximum,
the request will be rejected with an HTTP 400 error.
In the following example, the GET
request includes a
timeout
of 10 seconds.
curl 'https://docs-examples.firebaseio.com/rest/retrieving-data.json?timeout=10s'
Filtering Data
We can construct queries to filter data based on various factors. To start, you specify how you want your data to be filtered using the orderBy
parameter. Then, you combine orderBy
with any of the other five parameters:
limitToFirst
, limitToLast
, startAt
, endAt
,
and equalTo
.
Since all of us at Firebase think dinosaurs are pretty cool, we'll use a snippet from a sample database of dinosaur facts to demonstrate how you can filter data:
{ "lambeosaurus": { "height": 2.1, "length": 12.5, "weight": 5000 }, "stegosaurus": { "height": 4, "length": 9, "weight": 2500 } }
We can filter data in one of three ways: by child key, by key, or by
value. A query starts with one of these parameters, and then must be combined with one or more of the following parameters: startAt
, endAt
, limitToFirst
, limitToLast
, or equalTo
.
Filtering by a specified child key
We can filter nodes by a common child key by passing that key to the orderBy
parameter. For example, to retrieve all dinosaurs with a height greater than 3, we can do the following:
curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="height"&startAt=3&print=pretty'
Any node that does not have the child key we're filtering on will be sorted with a value of
null
. For details on how data is
ordered, see How Data is Ordered.
Firebase also supports queries ordered by deeply nested children, rather than only children one level down. This is useful if you have deeply nested data like this:
{ "lambeosaurus": { "dimensions": { "height" : 2.1, "length" : 12.5, "weight": 5000 } }, "stegosaurus": { "dimensions": { "height" : 4, "length" : 9, "weight" : 2500 } } }
To query the height now, we use the full path to the object rather than a single key:
curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="dimensions/height"&startAt=3&print=pretty'
Queries can only filter by one key at a time. Using the orderBy
parameter multiple
times on the same request throws an error.
Filtering by key
We can also filter nodes by their keys using the orderBy="$key"
parameter. The
following example retrieves all dinosaurs with a name starting with the letter a
through m
:
curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="$key"&startAt="a"&endAt="m"&print=pretty'
Filtering by value
We can filter nodes by the value of their child keys using the orderBy="$value"
parameter. Let's say the dinosaurs are having a dino sports competition and we're keeping
track of their scores in the following format:
{ "scores": { "bruhathkayosaurus": 55, "lambeosaurus": 21, "linhenykus": 80, "pterodactyl": 93, "stegosaurus": 5, "triceratops": 22 } }
To retrieve all dinosaurs with a score higher than 50, we could make the following request:
curl 'https://dinosaur-facts.firebaseio.com/scores.json?orderBy="$value"&startAt=50&print=pretty'
See How Data is Ordered for an explanation on
how null
, boolean, string, and object values are sorted when using
orderBy="$value"
.
Complex Filtering
We can combine multiple parameters to construct more complex queries.
Limit Queries
The limitToFirst
and limitToLast
parameters are used to set a
maximum number of children for which to receive data. If we set a limit of 100, we will only
receive up to 100 matching children. If we have less than 100 messages stored in our
database, we will receive every child. However, if we have over 100 messages, we will only
receive data for 100 of those messages. These will be the first 100 ordered messages if we are
using limitToFirst
or the last 100 ordered messages if we are using
limitToLast
.
Using our dinosaur facts database and orderBy
, we can find the two
heaviest dinosaurs:
curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="weight"&limitToLast=2&print=pretty'
Similarly, we can find the two shortest dinosaurs by using limitToFirst
:
curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="height"&limitToFirst=2&print=pretty'
We can also conduct limit queries with orderBy="$value"
. If we want to create a
leaderboard with the top three highest scoring dino sports competitors, we could do the
following:
curl 'https://dinosaur-facts.firebaseio.com/scores.json?orderBy="$value"&limitToLast=3&print=pretty'
Range Queries
Using startAt
, endAt
, and equalTo
allows us to choose
arbitrary starting and ending points for our queries. For example, if we wanted to find all
dinosaurs that are at least three meters tall, we can combine orderBy
and
startAt
:
curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="height"&startAt=3&print=pretty'
We can use endAt
to find all dinosaurs whose names come before Pterodactyl
lexicographically:
curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="$key"&endAt="pterodactyl"&print=pretty'
We can combine startAt
and endAt
to limit both ends of our query.
The following example finds all dinosaurs whose name starts with the letter "b":
curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="$key"&startAt="b"&endAt="b\uf8ff"&print=pretty'
Range queries are also useful when you need to paginate your data.
Putting it all together
We can combine all of these techniques to create complex queries. For example, maybe you want to find the name of all dinosaurs that are shorter than or equal in height to our favorite kind, Stegosaurus:
MY_FAV_DINO_HEIGHT=`curl "https://dinosaur-facts.firebaseio.com/dinosaurs/stegosaurus/height.json"` curl "https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy=\"height\"&endAt=${MY_FAV_DINO_HEIGHT}&print=pretty"
How Data is Ordered
This section explains how your data is ordered when using each of the three filtering parameters.
orderBy
When using orderBy
with the name of a child key, data that contains the specified
child key will be ordered as follows:
-
Children with a
null
value for the specified child key come first. -
Children with a value of
false
for the specified child key come next. If multiple children have a value offalse
, they are sorted lexicographically by key. -
Children with a value of
true
for the specified child key come next. If multiple children have a value oftrue
, they are sorted lexicographically by key. - Children with a numeric value come next, sorted in ascending order. If multiple children have the same numerical value for the specified child node, they are sorted by key.
- Strings come after numbers, and are sorted lexicographically in ascending order. If multiple children have the same value for the specified child node, they are ordered lexicographically by key.
- Objects come last, and sorted lexicographically by key in ascending order.
orderBy="$key"
When using the orderBy="$key"
parameter to sort your data, data will be returned
in ascending order by key as follows. Keep in mind that keys can only be strings.
- Children with a key that can be parsed as a 32-bit integer come first, sorted in ascending order.
- Children with a string value as their key come next, sorted lexicographically in ascending order.
orderBy="$value"
When using the orderBy="$value"
parameter to sort your data, children will be
ordered by their value. The ordering criteria is the same as data ordered by a child key,
except the value of the node is used instead of the value of a specified child key.
orderBy="$priority"
When using the orderBy="$priority"
parameter to sort your data, the ordering of
children is determined by their priority and key as follows. Keep in mind that priority values
can only be numbers or strings.
- Children with no priority (the default) come first.
- Children with a number as their priority come next. They are sorted numerically by priority, small to large.
- Children with a string as their priority come last. They are sorted lexicographically by priority.
- Whenever two children have the same priority (including no priority), they are sorted by key. Numeric keys come first (sorted numerically), followed by the remaining keys (sorted lexicographically).
For more information on priorities, see the API reference.
Streaming from the REST API
Firebase REST endpoints support the EventSource / Server-Sent Events protocol, making it easy to stream changes to a single location in our Firebase database.
To get started with streaming, we will need to do the following:
-
Set the client's Accept header to
text/event-stream
- Respect HTTP Redirects, in particular HTTP status code 307
-
Include the
auth
query parameter if the Firebase database location requires permission to read
In return, the server will send named events as the state of the data at the requested URL changes. The structure of these messages conforms to the EventSource protocol:
event: event name data: JSON encoded data payload
The server may send the following events:
put | The JSON-encoded data will be an object with two keys: path and data The path points to a location relative to the request URL The client should replace all of the data at that location in its cache with the data given in the message |
patch | The JSON-encoded data will be an object with two keys: path and data The path points to a location relative to the request URL For each key in the data, the client should replace the corresponding key in its cache with the data for that key in the message |
keep-alive | The data for this event is null, no action is required |
cancel | The data for this event is null This event will be sent if the Firebase Realtime Database Security Rules cause a read at the requested location to no longer be allowed |
auth_revoked | The data for this event is a string indicating that a the credential has expired This event will be sent when the supplied auth parameter is no longer valid |
Below is an example of a set of events that the server may send:
// Set your entire cache to {"a": 1, "b": 2} event: put data: {"path": "/", "data": {"a": 1, "b": 2}} // Put the new data in your cache under the key 'c', so that the complete cache now looks like: // {"a": 1, "b": 2, "c": {"foo": true, "bar": false}} event: put data: {"path": "/c", "data": {"foo": true, "bar": false}} // For each key in the data, update (or add) the corresponding key in your cache at path /c, // for a final cache of: {"a": 1, "b": 2, "c": {"foo": 3, "bar": false, "baz": 4}} event: patch data: {"path": "/c", "data": {"foo": 3, "baz": 4}}
If you're using Go, check out Firego, a third-party wrapper around the Firebase REST and Streaming APIs.