Designed by Freepik

Hi, today we’ve got another non-Android tutorial, but about about something that affects Android development experience a lot. Firebase. If you worked with Firebase at least more than just simple samples/insert/fetch, then you probably know about one downside of Firebase using just Android SDK.

Problem

The problem is not just lot’s of backend related code in our apps, it’s duplication. If you compare basic server with REST API, then you have a nice abstraction and you never need to know about what’s backend doing up there. That’s a good programming principle.

Now with Firebase your app is doing all your database work. And it’s fine when you just insert/update one table (node), but in real apps it’s never like that. With one update there’s at least two – three nodes to update with it. Hence, more code in your app. And if you have web, iOS app it means you’ll have duplicated code everywhere.

What’s the problem with it? You’ll have to test 3 times more, spend 3 times more writing code etc. And your changes have to be synced very good with other platforms – good communication of changes. Imagine :

Ah, yeah iOS guy forgot to update his client code, that’s why everything crashed

By no means, that’s not a good practice.

For example, creating new user: uploading picture to storage, saving user to database, saving to geofire. And could be even more. You can use fancy RxJava chains, but it’s still duplication

Solution

Luckily, there’s Node.js and Java server admin SDK’s. So that you can build good old REST API for inserting/updating data to firebase and use client SDK’s for fetching/listening for data. I’d recommend to write server endpoints for every insertion. Even if it’s just one node.

Why so? Well, because sometimes in the future your code base will grow and where it was just one node it will be three and then you’ll have to create a new endpoint and change all three (web, iOS, Android app’s code). When if you create endpoint from beginning, you’ll just change server code and clients stay the same

This reminded me of one of the reasons why we have getters/setters for our POJO’s. Don’t you find it redundant to create getters/setters for primitives when you can just access/change them by making public? The reason behind it is that sometime in the future you might change the logic behind your POJO’s and simple getName method might do some more than just return field string. If you had a getter, your clients won’t need to change at all, otherwise you’ll get to change every single line where you access it. Now imagine it was a library.

Cloud Functions

Alright, so let’s start writing some server code. Cloud functions use Node.js. First of all, you’ll need to have a firebase project. Create one if you don’t have. Then install firebase client with this command

npm install -g firebase-tools 1 npm install - g firebase - tools

npm stands for Node Package Manager, if you don’t have one, install it from here

Run this command then, it will open browser to login

firebase login 1 firebase login

After you’re logged in to Firebase create new folder, open it and run this command

firebase init functions 1 firebase init functions

Check out newly created files.

Simple Function

Let’s create simple node insertion. Replace code in your index.js with this

const functions = require('firebase-functions'); const admin = require('firebase-admin'); admin.initializeApp(functions.config().firebase); exports.addMessage = functions.https.onRequest((req, res) => { const original = req.query.text; admin.database().ref('/messages').push({original: original}).then(snapshot => { res.redirect(303, snapshot.ref); }); }); 1 2 3 4 5 6 7 8 9 10 const functions = require ( 'firebase-functions' ) ; const admin = require ( 'firebase-admin' ) ; admin . initializeApp ( functions . config ( ) . firebase ) ; exports . addMessage = functions . https . onRequest ( ( req , res ) = > { const original = req . query . text ; admin . database ( ) . ref ( '/messages' ) . push ( { original : original } ) . then ( snapshot = > { res . redirect ( 303 , snapshot . ref ) ; } ) ; } ) ;

Then run those commands to deploy it

npm install firebase deploy --only functions 1 2 npm install firebase deploy -- only functions

After it’s done, you’ll see url for your new endpoint, it will be ending with /addMessage. And you can see it in Firebase console

Run this url with ?test=Hello Functions attribute in your browser to test your first Firebase Function.

Geofire

So I had this app from RecyclerView for Firebase Geofire post and saving user to database and geofire I implemented with RxJava. For something simple it looks ok, but let’s make it as an API call. Open your index.js file and replace it with this code

const functions = require('firebase-functions'); const admin = require('firebase-admin'); const GeoFire = require('geofire'); admin.initializeApp(functions.config().firebase); const geoFire = new GeoFire(admin.database().ref('/geofire')); exports.addUser = functions.https.onRequest((req, res) => { const user = req.body; var newUser = admin.database().ref('/users').push(); newUser.set(user).then(snapshot => { var location = [user.latitude, user.longitude]; geoFire.set(newUser.key, location).then(function() { res.send(200, "ok"); }); }); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const functions = require ( 'firebase-functions' ) ; const admin = require ( 'firebase-admin' ) ; const GeoFire = require ( 'geofire' ) ; admin . initializeApp ( functions . config ( ) . firebase ) ; const geoFire = new GeoFire ( admin . database ( ) . ref ( '/geofire' ) ) ; exports . addUser = functions . https . onRequest ( ( req , res ) = > { const user = req . body ; var newUser = admin . database ( ) . ref ( '/users' ) . push ( ) ; newUser . set ( user ) . then ( snapshot = > { var location = [ user . latitude , user . longitude ] ; geoFire . set ( newUser . key , location ) . then ( function ( ) { res . send ( 200 , "ok" ) ; } ) ; } ) ; } ) ;

Here we create new function called addUser, we pass user object in request body, save it to database and then to geofire using its location. No need to declare HTTP method. Call this command from functions folder to add geofire dependency

npm install geofire firebase --save 1 npm install geofire firebase -- save

Then deploy using the command from above and you can build your good old Retrofilt REST API.

Alright, that’s was just a slight overview of Firebase Cloud Functions, what I covered was JavaScript Admin SDK, so it’s not new, but we’ll go deeper into more functionality in the future.

You can get Server source code here, Android here. And definitely check second part or this series, where we’ll look at Triggers, new cool feature to extend your Firebase functionality. Don’t forget to subscribe, follow me on Facebook, Twitter, G+ and share with friends if you think they will benefit from it!