Launching Beeline with Firebase

Launching Beeline with Firebase
Oct 2017
Who is this guy?
CTO at beeline.co
@chetbox
What is Beeline?
We make journeys
more enjoyable
What is Beeline?
Prototype
What is Beeline?
What is Beeline?
The app
The big
challenge
● 3 months
● Android and iOS
● User accounts
● Data storage
● Analytics
User accounts
Just use Firebase Authentication
Data storage
Data storage Realm + S3 → ?
Data storage
Why Firebase Database?
● Hosted
● Automatic sync to server
● iOS and Android SDK
● Open-source UI libraries
Data storage
What’s different?
● NoSQL
● Security enforced by rules.json
● Realtime
● Reactive UI
rules.json
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
rules.json
{
"rules": {
"destinations": {
"$user_id": {
".validate": "newData.hasChildren(['latitude', 'longitude'])”,
".read": "auth != null && auth.uid == $user_id",
".write": "auth != null && auth.uid == $user_id",
".indexOn": [
"isFavourite"
],
"$id": {
"latitude": {
".validate": "newData.isNumber() && newData.val() >= -90 &&
newData.val() <= 90"
},
"longitude": {
".validate": "newData.isNumber() && newData.val() >= -180 &&
newData.val() <= 180"
},
"name": {
".validate": "newData.isString()"
}
...
Data storage
FIREBASE WARNING:
set at /destinations/abc/def failed:
permission_denied
rules.bolt
path /destinations/{user_id}/{id} {
latitude: Number;
longitude: Number;
name: String | Null;
}
path /destinations/{user_id} {
read() {auth && auth.uid == user_id}
write() {auth && auth.uid == user_id}
}
rules.bolt
path /destinations/{user_id}/{id}
is Destination;
type LatLon {
latitude: Number;
longitude: Number;
}
type Destination extends LatLon {
name: String | Null;
}
rules.bolt
type LatLon {
latitude: Number;
longitude: Number;
validate() {
latitude >= -90 &&
latitude <= 90 &&
longitude >= -180 &&
longitude <= 180
}
}
rules.bolt
path /destinations/{user_id} {
read() { isSignedInUser(user_id) }
write() { isSignedInUser(user_id) }
}
isSignedInUser(user_id) {
isSignedIn() && auth.uid === user_id
}
isSignedIn() {
auth != null
}
Test your rules!
Test your rules!
Targaryen is a former Great House of Westeros and
was the ruling royal House of the Seven Kingdoms
for three centuries, before it was deposed during
Robert's Rebellion and House Baratheon replaced it
as the new royal House. The few surviving
Targaryens fled into exile. Currently based in Essos,
House Targaryen seeks to retake the Seven
Kingdoms from House Lannister, who formally
replaced House Baratheon as the royal House
following the destruction of the Great Sept of Baelor.
http://gameofthrones.wikia.com/wiki/House_Targaryen
Test your rules!
targaryen = require 'targaryen'
rules = require 'rules.json'
describe 'Destinations', ->
beforeEach ->
targaryen.setFirebaseRules rules
targaryen.setFirebaseData
destinations:
queen:
buckingham_palace:
latitude: 51.5013021
longitude: -0.148308
it 'cannot be read publicly', ->
expect targaryen.users.unauthenticated
.cannotRead '/destinations'
Test your rules!
it 'can be read by owner', ->
expect uid: 'queen'
.canRead '/destinations/queen'
it 'cannot be read by others', ->
expect targaryen.users.unauthenticated
.cannotRead '/destinations/queen'
expect uid: 'mayor'
.cannotRead '/destinations/queen'
Test your rules!
it 'can be created by owner', ->
expect uid: 'queen'
.canWrite '/destinations/queen/palace,
latitude: 51.501364
longitude: -0.14189
Test your rules!
// package.json
{
"scripts": {
"test": "firebase-bolt rules.bolt &&
node node_modules/jasmine/bin/jasmine.js"
}
}
$ npm test
Automatic
deployment
$ npm test
bolt: Generating rules.json...
Started
...............................................................
...............................................................
...............................................................
..........................
215 specs, 0 failures
Finished in 0.5 seconds
The command "npm test" exited with 0.
$ firebase --project beeline-test-e7288 deploy
Deploying to 'master' beeline-test-e7288
=== Deploying to 'beeline-test-e7288'...
i deploying database, functions
✔ database: rules ready to deploy.
i starting release process (may take several minutes)...
✔ Deploy complete!
.travis.yml
language: node_js
node_js: "6"
install:
- npm install
script:
- npm test
deploy:
- on:
branch: master
skip_cleanup: true
script: firebase --project beeline-test-e7288
--token "$FIREBASE_TOKEN" deploy
Android/iOS
project structure
- app
- src
- debug
- google-services.json
- release
- google-services.json
- Beeline
- GoogleService-Info.plist
- GoogleService-Info-Test.plist
Android
@IgnoreExtraProperties
data class Destination(
val latitude: Double = 0.0,
val longitude: Double = 0.0,
val name: String? = null,
)
val ref = FirebaseDatabase.getInstance()
.getReference("/destinations/user1/dest1")
// Write data
ref.setValue(Destination(51.5, 0))
Android
// Read data
ref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val destination =
snapshot.getValue(Destination::class.java)
// ...
}
override fun onCancelled(error: DatabaseError) {}
})
iOS
// Write data
ref.setValue([
"latitude": 51.5,
"longitude": 0
])
Querying
ref.orderBy("date-string")
.startAt("2017-04-16")
.endAt("2017-04-23")
ref.orderBy("date-string")
.equalTo("2017-04-24")
.limitToLast(1)
Cloud functions
to the rescue!
Which
language?
Aggregating
// functions/index.ts
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
const db = admin.database();
export const all_destinations =
functions.database.ref('/destinations/{userId}/{id}')
.onWrite((event) =>
db.ref(`/all-destinations/${event.params.id}`)
.set(event.data.val());
);
Cloud function
security
sudo rm -rf /
Never do this.
Cloud function
security
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(Object.assign(
{databaseAuthVariableOverride: {
uid: "stats@cloudfunction.beeline.co"
},
functions.config().firebase
);
const db = admin.database();
Cloud function
security
path /stats/user/{user_id} {
read() { isSignedInUser(user_id) }
write() { isCloudFunctionUser('stats') }
}
isCloudFunctionUser(name) {
auth.uid === name + '@cloudfunction.beeline.co'
}
Cloud function
testing tips
● Use .val()
● Unit test your data logic
● Unit test your functions (fiddly)
https://firebase.google.com/docs/functions/unit-testing
● Set up error notifications for production
https://console.cloud.google.com/errors
.travis.yml
language: node_js
node_js: "6"
install:
- npm install
- (cd functions && npm install)
script:
- npm test
- (cd functions && npm test)
deploy:
- on:
branch: master
skip_cleanup: true
script: firebase --project beeline-test-e7288
--token "$FIREBASE_TOKEN" deploy
And then?
Get fancy
● User permissions as database
rules
● Index your data
● Automate with analytics events
● Build web dashboards
Permissions for
special users
path /permissions/{user_id} {
change_permissions: Boolean | Null;
internal_feature_1: Boolean | Null;
beta_feature_1: Boolean | Null;
write(){ userHasPermission('change_permissions') }
}
userHasPermission(permission) {
root.permissions[auth.uid][permission] === true
}
Indexing
// index /destinations by name
export const destinations_index =
functions.database.ref('/destinations/{userId}/{id}')
.onWrite((event) => {
if (event.data.val().name)
return db.ref('/destinations-index')
.child(event.data.val().name.toLowerCase())
.child(event.params.userId)
.child(event.params.id)
.set(Date.now());
});
Automatically
save device
metadata
exports.ride_saveAppAndDeviceInfo =
functions.analytics.event('ride_started').onLog(
(event: functions.Event<functions.analytics.AnalyticsEvent>)
=> {
const user = event.data.user;
const uid = user && user.userId;
const rideId = event.data.params && event.data.params.value;
if (uid && rideId) {
return db.ref(`/rides/${uid}/${rideId}`).update({
app_version: user.appInfo.appVersion,
phone_os: user.appInfo.appPlatform,
phone_os_version: user.deviceInfo.platformVersion,
phone_model: user.deviceInfo.mobileModelName,
phone_manufacturer: user.deviceInfo.mobileBrandName
});
}
});
// Be careful of race conditions
Web dashboard
Web dashboard
Web admin
Web dashboard
Web dashboard
What we like
so far
● Easy to set up
● Easy to integrate
● Realtime DB updates
● Minimal backend code
● Detailed docs
What we like
less so far
● A bit of a learning curve
● Lacking examples
● Limited querying
● Developing functions is slow
● Slow to load lots of data
● “Open source”
● In flux
What’s next
● More in-depth stats
● Large data → Long term (cheaper)
storage
● Emails/push for in-app events
● Cloud Firestore?
Questions?
https://beeline.co
@chetbox
1 of 56

More Related Content

What's hot(20)

async/await in Swiftasync/await in Swift
async/await in Swift
Peter Friese217 views
AuthenticationAuthentication
Authentication
soon892 views
GoogleGoogle
Google
soon978 views
DeployingDeploying
Deploying
soon1.1K views
iOS5 NewStuffiOS5 NewStuff
iOS5 NewStuff
deenna_vargilz1.2K views
Great Developers StealGreat Developers Steal
Great Developers Steal
Ben Scofield1.7K views
Deep Dive: AWS Command Line InterfaceDeep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line Interface
Amazon Web Services5.6K views
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUG
Ben Scofield910 views
Django - 次の一歩 gumiStudy#3Django - 次の一歩 gumiStudy#3
Django - 次の一歩 gumiStudy#3
makoto tsuyuki2.6K views
Load Data Fast!Load Data Fast!
Load Data Fast!
Karwin Software Solutions LLC10.2K views
Node.js and ParseNode.js and Parse
Node.js and Parse
Nicholas McClay25.6K views
My app is secure... I thinkMy app is secure... I think
My app is secure... I think
Wim Godden1.8K views
Play á la RailsPlay á la Rails
Play á la Rails
Sebastian Nozzi1.2K views

Similar to Launching Beeline with Firebase(20)

Recently uploaded(20)

Web Dev - 1 PPT.pdfWeb Dev - 1 PPT.pdf
Web Dev - 1 PPT.pdf
gdsczhcet44 views
METHOD AND SYSTEM FOR PREDICTING OPTIMAL LOAD FOR WHICH THE YIELD IS MAXIMUM ...METHOD AND SYSTEM FOR PREDICTING OPTIMAL LOAD FOR WHICH THE YIELD IS MAXIMUM ...
METHOD AND SYSTEM FOR PREDICTING OPTIMAL LOAD FOR WHICH THE YIELD IS MAXIMUM ...
Prity Khastgir IPR Strategic India Patent Attorney Amplify Innovation22 views
CXL at OCPCXL at OCP
CXL at OCP
CXL Forum158 views
Liqid: Composable CXL PreviewLiqid: Composable CXL Preview
Liqid: Composable CXL Preview
CXL Forum114 views
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf
Eleanor McHugh31 views

Launching Beeline with Firebase