Wednesday, December 6, 2017

Express app using firebase HTTP Trigger

if you want to know about firebase and firebase cloud functions before jumping into this article, please visit the following links.

1) Firebase RealTime Database
2) Firebase Authentication Service
3) Why we need cloud functions
4) Introduction to cloud functions

HTTP Trigger:
It will be invoked based on the rest call from the client. You can perform the pre validation of data before writing into db, connect to third party services like git, slack etc.

Express App using HTTP Trigger:

Please checkout the following projects from github if you want to play around.

Web Client:
1) https://github.com/fullstacktechnos/firebase-frontend

Firebase Functions:
2) https://github.com/fullstacktechnos/firebase-functions


* Following code sends a message from the web app using http post.

firebase.auth().currentUser.getToken().then(function(token) {
                    let restEndPoint = 'https://us-central1-testapp.cloudfunctions.net/app/writemsg';
                    console.log('Sending request to', restEndPoint, 'with ID token in Authorization header.');
                    var req = new XMLHttpRequest();
                    req.onload = function() {
                        console.log(req.responseText);
                    }.bind(this);
                    req.onerror = function() {
                        console.log('There was an error');
                    }.bind(this);
                    req.open('POST', restEndPoint, true);
                    req.setRequestHeader('Authorization', 'Bearer ' + token);
                    req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
                    req.send("message="+content);
                }.bind(this))
                .catch(function(err) { console.log('No token found')});


- In the above code we are passing a message using http post request to the rest endpoint 'writemsg'.
- User is sending the message after he/she login. So we can pass the token in Authorization header for verification in backend.
- https://us-central1-testapp.cloudfunctions.net/app/ is the rest api base url. You can find it in firebase project under Functions or in the console at the time of deployment.


* Following cloud function code

- creates an express app
- invoke the http trigger when the rest api is called
- validate the user token
- go to the http post handler
- validate the input data and write into the realtime database.


const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

//http trigger
const express = require('express');
const cookieParser = require('cookie-parser')();
const cors = require('cors')({ origin: true });
const app = express();

const validateFirebaseIdToken = (req, res, next) => {
  console.log('Check if request is authorized with Firebase ID token');

  if ((!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) &&
    !req.cookies.__session) {
    console.error('No Firebase ID token was passed as a Bearer token');
    res.status(403).send('Unauthorized');
    return;
  }

  let idToken;
  if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
    console.log('Found "Authorization" header');
    // Read the ID Token from the Authorization header.
    idToken = req.headers.authorization.split('Bearer ')[1];
  } else {
    console.log('Found "__session" cookie');
    // Read the ID Token from cookie.
    idToken = req.cookies.__session;
  }

  admin.auth().verifyIdToken(idToken).then(decodedIdToken => {
    console.log('ID Token correctly decoded', decodedIdToken);
    req.user = decodedIdToken;
    next();
  }).catch(error => {
    console.error('Error while verifying Firebase ID token:', error);
    res.status(403).send('Unauthorized');
  });
};

app.use(cors);
app.use(cookieParser);
app.use(validateFirebaseIdToken);

app.post('/writemsg', (req, res) => {
  if (req.body.message === undefined) {
    res.status(400).send('No message defined!');
  } else {
    console.log('input data :: ' + req.body.message);
    
    //Insert message to Realtime Database node "messages"
    admin.database().ref('messages').push({
      type: 'Rest',
      description: req.body.message
    })
    .then(() => res.status(200).send('Msg updated Successfully'))
    .catch( error => res.status(401).send('Not able to update the msg'))
  }
});

exports.app = functions.https.onRequest(app);

* Note:
To know more please visit the following link.
https://firebase.google.com/docs/functions/http-events

Useful Reads:
http://www.fullstacktechnos.com/2017/12/firebase-realtime-database-trigger.html
http://www.fullstacktechnos.com/2017/12/firebase-authentication-trigger.html

No comments:

Post a Comment