Firebase offers a very flexible and secure way to save text-based data.
This guide will show some of the most common scenarios and it will explain how to use Rules for your database. It is also written from an ActionScript and SQL perspective.
Before you start integrating Firebase Database in your iOS projects you must add the following exceptions in the iPhone
section from your descriptor file.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>firebaseio.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
Firebase Auth and Storage don't rely on these rules to function.
The data saved in the Firebase database is structured like a tree. Each 'branch' can have its own branches and those sub branches can have their own sub branches.
The Firebase data can only be retrieved as JSON, you will require to use the JSON class to convert the data into an ActionScript Object.
The Firebase Rules are a flexible way to set permissions on who can access certain data.
By default all the data is private and can only be accessed by Authenticated users.
To modify the Rules follow these steps:
- Open the Firebase console
- Select your project.
- Click on the Database option from the left side menu.
- Click on
RULES
from the top menu.
In the following example we will make the contents of a node named news
available to read for everyone on the Internet.
{
"rules": {
"news": {
".read": true,
".write": false
}
}
}
These rules mean that anyone can read the news
node, but no one can write (modify) it.
Now we want to make a public message board where anyone can post anything, one example could be an app that receives anonymous feedback.
{
"rules": {
"feedback": {
".read": true,
".write": true
}
}
}
This is not a very good idea since users that know how Firebase works can manipulate the messages or delete them.
For this case it is recommended to use Anonymous
auth.
In the following example we will make the contents of a node named specialoffers
available to read for only registered users from your project.
{
"rules": {
"specialoffers": {
".read": "auth != null",
".write": false
}
}
}
This rule is almost the same as the default one, the only difference is that it specifies which node to protect.
This is where Firebase auth and rules are best used; each user can have their own data that they can only read and write.
A common example is an app where users can manage a todo list.
{
"rules": {
"todos": {
"$user_id": {
".read": "$user_id === auth.uid",
".write": "$user_id === auth.uid"
}
}
}
}
We have a main todos
node. Inside that node each user will have their own sub node.
Each sub node will contain the todos from the specified user.
The auth.uid
parameter means the following:
auth
is an Object inside an Authentication Token (see below).uid
is an unique id that is assigned to each user in your Firebase project. This uid is also known as thelocalId
$user_id
is an arbitrary variable name that will contain the value from the auth.uid
, this way the user's node is named the same as its uid. Making impossible to be repeated or be loaded by accident by another user.
An Authentication Token is an encoded string that contains information about the user that is trying to perform an operation against the database.
There are several ways to generate these tokens, this guide will only explain how to do it using Google Identity Toolkit so you won't require to do Cryptographic wizardry.
For more detailed information on how to generate and manage an authToken
please consult the Firebase Auth guide.
Once you have got a fresh authToken
you are ready to perform secure operations against the Firebase Database and Firebase Storage.
Connecting to the database is rather simple, you only require an URLRequest
and an URLLoader
.
To load a Public resource use the following code (this is the equivalent of a SELECT
in SQL
):
private function loadNews():void
{
var request:URLRequest = new URLRequest("https://<YOUR-PROJECT-ID>.firebaseio.com/news.json");
var loader:URLLoader = new URLLoader();
loader.addEventListener(flash.events.Event.COMPLETE, newsLoaded);
loader.load(request);
}
private function newsLoaded(event:flash.events.Event):void
{
trace(event.currentTarget.data);
}
A simple GET
request (the default for URLRequest
) is enough. Remember to always add .json
after the name of the node you want to read.
To load a Private resource use the following code:
private function loadSpecialOffers(authToken:String):void
{
var request:URLRequest = new URLRequest("https://<YOUR-PROJECT-ID>.firebaseio.com/specialoffers.json?auth="+authToken);
var loader:URLLoader = new URLLoader();
loader.addEventListener(flash.events.Event.COMPLETE, offersLoaded);
loader.load(request);
}
private function offersLoaded(event:flash.events.Event):void
{
trace(event.currentTarget.data);
}
Very similar to the previous one, the only difference is the auth
parameter in the URL.
Changes in the database can be read at realtime. Instead of using an URLLoader
you must use an URLStream
with a special URLRequestHeader
.
In this case we specify to read the contents of the breakingnews
node.
private var myStream:URLStream;
private function loadLiveFeed():void
{
var header:URLRequestHeader = new URLRequestHeader("Accept", "text/event-stream");
var request:URLRequest = new URLRequest("https://<YOUR-PROJECT-ID>.firebaseio.com/breakingnews.json");
request.requestHeaders.push(header);
myStream:URLStream = new URLStream();
myStream.addEventListener(ProgressEvent.PROGRESS, progress);
myStream.load(request);
}
private function progress(event:ProgressEvent):void
{
var message:String = myStream.readUTFBytes(myStream.bytesAvailable);
trace(message);
}
We used a ProgressEvent.PROGRESS
instead of the usual Event.COMPLETE
. Everytime the data changes the ProgressEvent
will be fired with the path and the data that was modified.
Remember to remove the event listener once you have finished working with the realtime data or it will continue listening to it.
Auth works exactly the same as with non-realtime data, you only need to provide the auth
parameter with a valid authToken
in the URL.
You can add (INSERT)
, remove (DELETE)
and modify (UPDATE)
data from the database. You only need to send your data JSON
encoded.
The auth
parameter is only required when you want to modify private resources.
In this example we are adding an entry to a node named journal
with the following parameters: title
, description
and timestamp
.
private function saveEntry(title:String, description:String):void
{
var myObject:Object = new Object();
myObject.title = title;
myObject.description = description;
myObject.timestamp = new Date().getTime();
var request:URLRequest = new URLRequest("https://<YOUR-PROJECT-ID>.firebaseio.com/journal.json");
request.data = JSON.stringify(myObject);
request.method = URLRequestMethod.POST;
var loader:URLLoader = new URLLoader();
loader.addEventListener(flash.events.Event.COMPLETE, entrySent);
loader.load(request);
}
private function entrySent(event:flash.events.Event):void
{
trace(event.currentTarget.data);
}
A successful response will look like the following JSON structure:
{
"name": "-KRQvdxVELCITxtUynvx"
}
Everytime you push new data to a node, Firebase will automatically generate an unique id
for it. The following image shows how data is being structured.
We can only delete nodes or subnodes but not specific values inside those nodes unless we set those values to blank (see below for modifying data).
To delete a node you only need to specify its path an add a special URLRequestHeader
.
private function deleteEntry():void
{
var header:URLRequestHeader = new URLRequestHeader("X-HTTP-Method-Override", "DELETE");
var request:URLRequest = new URLRequest("https://<YOUR-PROJECT-ID>.firebaseio.com/journal.json");
request.method = URLRequestMethod.POST;
request.requestHeaders.push(header);
var loader:URLLoader = new URLLoader();
loader.addEventListener(flash.events.Event.COMPLETE, entryDeleted);
loader.load(request);
}
private function entryDeleted(event:flash.events.Event):void
{
trace(event.currentTarget.data);
}
This will delete the complete journal
node including all its subnodes.
If you only want to delete an specific sub node you must change the url path, in this case we want to delete the node from the previous example:
https://<YOUR-PROJECT-ID>.firebaseio.com/journal.json
to
https://<YOUR-PROJECT-ID>.firebaseio.com/journal/-KRQvdxVELCITxtUynvx.json
A successful response returns a null
value.
Sometimes we just want to change a single value from a node. We only need to specify the path of the node, the data to be changed and a special URLRequestHeader
.
private function updateEntry(title:String, description:String):void
{
var header:URLRequestHeader = new URLRequestHeader("X-HTTP-Method-Override", "PATCH");
var myObject:Object = new Object();
myObject.title = title;
myObject.description = description;
var request:URLRequest = new URLRequest("https://<YOUR-PROJECT-ID>.firebaseio.com/journal/-KRQvdxVELCITxtUynvx.json");
request.data = JSON.stringify(myObject);
request.method = URLRequestMethod.POST;
request.requestHeaders.push(header);
var loader:URLLoader = new URLLoader();
loader.addEventListener(flash.events.Event.COMPLETE, entryUpdated);
loader.load(request);
}
private function entryUpdated(event:flash.events.Event):void
{
trace(event.currentTarget.data);
}
A successful response will contain the values that were modified, in this case the title
and description
:
{
"title": "New Title",
"description": "Updated description"
}
Make sure to always set the correct path or you may modify other nodes by accident.
At the beginning of this guide we mentioned that Firebase excels at managing user specific data.
To accomplish this, you only require to add the user localId
as the node name.
For example, we want that each user has their independent journal that they can only read and modify, the rules should look as follows:
{
"rules": {
"journals": {
"$user_id": {
".read": "$user_id === auth.uid",
".write": "$user_id === auth.uid"
}
}
}
}
When you want to modify or read their journal you need to specify the users localId
(known as uid
inside the rules) and authToken
as part of the URL.
private function loadPrivateJournal(localId:String, authToken:String):void
{
var request:URLRequest = new URLRequest("https://<YOUR-PROJECT-ID>.firebaseio.com/journals/"+localId+".json?auth="+authToken);
var loader:URLLoader = new URLLoader();
loader.addEventListener(flash.events.Event.COMPLETE, journalLoaded);
loader.load(request);
}
private function journalLoaded(event:flash.events.Event):void
{
trace(event.currentTarget.data);
}
The localId
can be obtained after a successful Sign In
, Sign Up
or Get Account Info
request.
The auth
value can be obtained after a successful Refresh Token
request.
For more information on these values you can read the Firebase Auth guide.
Firebase allows you to use server variables for your fields. At the moment of this writing Firebase only offers a timestamp
variable.
To use a server variable you need to create a property on your payload with the following signature: {".sv": "variable_type"}
.
In the following example we are using the timestamp
variable so our message will use a Firebase timestamp instead of a local one from the user's device.
private function sendMessage(message:String, username:String):void
{
var myObject:Object = new Object();
myObject.message = message;
myObject.username = username;
myObject.timestamp = {".sv": "timestamp"};
var request:URLRequest = new URLRequest("https://<YOUR-PROJECT-ID>.firebaseio.com/messages.json");
request.method = URLRequestMethod.POST;
request.data = JSON.stringify(myObject);
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, messageSent);
loader.load(request);
}
private function messageSent(event:Event):void
{
trace(event.currentTarget.data);
}