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

Firebase Realtime Database 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

Realtime Database Trigger :

We can invoke realtime db trigger in response to any database events from the client.
From your web or mobile app when ever there is a database event, cloud realtime db trigger can be invoked. It is a post db operation.

For ex: User sends a msg called "stupid message" from the app to write into message node. If a db trigger is attached to the message node, it can listen to the onWrite() event, read the incoming msg, change to "Wonderful message" and stores back.

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 function from the web client will write a message to firebase realtime database having node "messages"

var ref = firebase.database().ref('messages');
                var data = {
                    type: 'Generic',
                    description: 'Stupid msg'
                }
                ref.push(data);



** Following cloud function in firebase will be invoked, sanitized the data and save it back.

//db trigger
function sanitize(msgDescription) {
  var sanitisedContent = msgDescription;
  sanitisedContent = sanitisedContent.replace(/\bstupid\b/ig, "wonderful");
  return sanitisedContent;
}
exports.sanitizeMessage = functions.database.ref('/messages/{mid}').onWrite(event => {
  const msg = event.data.val();

  //prevent calling same trigger again.
  if (msg.sanitized) {
    return;
  }
  console.log("Sanitizing new message : " + event.params.mid);
  console.log(msg);
  msg.sanitized = true;

  msg.description = sanitize(msg.description);
  return event.data.ref.set(msg);
})

*Please check the github project mention above for the working copy.

- The above db trigger (sanitizeMessage) will be invoked every time there is a new message write.
- It reads the incoming message after the message written into the db(as db triggers are post operation trigger), check the word "stupid" in it, if present change it to "wonderful" and writes back.

- If we write back to the same node again the same db trigger will be invoked which will continue for infinite loop. So to avoid the infinite looping we are checking at the beginning if the message is sanitized. If it is then we don't need to proceed.

- Its always better to return a promise from the trigger as mentioned in the last line of "sanitizeMessage" function. This way google function won't be killed until the promise is either resolved or rejected. So we can wait for the db operation to complete.

Event Handlers:
onWrite(), which triggers when data is created, destroyed, or changed in the Realtime Database.
onCreate(), which triggers when new data is created in the Realtime Database.
onUpdate(), which triggers when data is updated in the Realtime Database.
onDelete(), which triggers when data is deleted from the Realtime Database.

**Note:
For more information please visit:
https://firebase.google.com/docs/functions/database-events

Firebase Authentication Trigger

If you want to familiar with what is 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

We can trigger auth cloud functions that can run in response to user creation or deletion.

For ex: From your web or mobile app when ever there is a user signup you can invoke your auth trigger in the backend, which is a firebase cloud function, that will send a welcome email to the user. You don't need to duplicate sending welcome email code in your web and mobile apps. Common business logic can move to the server side.

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

First one is a frontend web app using which you can send request to your firebase backend.
Second one is your firebase cloud functions which will be triggered in specific conditions.

If you have issues setting up cloud function project please check the link Introduction to cloud functions above


** Following function from the web client will send a user registration request to firebase:


firebase.auth().signInWithEmailAndPassword(email, password)
                .then(function(result) {
                    console.log(result);
                })
                .catch(function(error) {
                    console.log('signIn error', error);
                })



** Following cloud function in firebase will be invoked and performed few extra work and save it.


//Auth trigger
exports.createUserAccount = functions.auth.user().onCreate(event => {
  const uid = event.data.uid;
  const email = event.data.email;
  const photoUrl = event.data.photoUrl || 'http://lorempixel.com/400/200/';
  const newUserRef = ref.child(`/users/${uid}`);

  return newUserRef.set({
    photoUrl: photoUrl,
    email: email
  })
})


- The above auth trigger will be invoked every time there is a new user creation in firebase.
- In the above function you can see that its checking for photo url which should come as a input from client, if it is not present then trigger is adding a default photo url.
- Once the data is ready trigger is writing to the child node(/users/useruid/) of user pointing to user id.
- Firebase stores User data in its own place which we cant change but we can store our own data into Real time database.

**Note:
For more information please visit:
https://firebase.google.com/docs/functions/auth-events

Useful Read :
http://www.fullstacktechnos.com/2017/12/firebase-realtime-database-trigger.html
http://www.fullstacktechnos.com/2017/12/express-app-using-firebase-http-trigger.html

Monday, November 20, 2017

Rest API using AWS Lamda, Serverless and Nodejs

Prerequisite

1) AWS Lamda - If you are not aware of lamda function, please visit the following link.

http://www.fullstacktechnos.com/2017/11/what-is-aws-lamda.html

2) Serverless Framework - I am using serverless to deploy my aws infrastructure. Please visit the following article to setup the serverless in your local box.
You don't need to create any project though.

http://www.fullstacktechnos.com/2017/11/create-your-first-nodejs-lamda-function.html

Setup

If you have configured serverless for aws successfully then verify the installations by typing the command in the terminal. Your version number may not match mine.

$node -v
v6.11.3
$sls -v
1.18.1
$aws --version
aws-cli/1.11.127 Python/3.6.2 Darwin/17.2.0 botocore/1.5.90
$cat ~/.aws/credentials 
[default]
aws_access_key_id=*******************
aws_secret_access_key=*****************


I have already created the sample nodejs lamda project with serverless. Please find the following  github link.


https://github.com/fullstacktechnos/serverless-lamda-test


Checkout the code.


git clone https://github.com/fullstacktechnos/serverless-lamda-test.git


handler.js : (lamda code goes here)

'use strict';

module.exports.helloWorld = (event, context, callback) => {
  const response = {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Origin': '*', // Required for CORS support to work
    },
    body: JSON.stringify({
      message: 'Go Serverless v1.0! Your function executed successfully!',
      input: event,
    }),
  };

  callback(null, response);
};


serverless.yml:


# Welcome to serverless. Read the docs
# https://serverless.com/framework/docs/

# Serverless.yml is the configuration the CLI
# uses to deploy your code to your provider of choice

# The `service` block is the name of the service
service: serverless-hello-world

# The `provider` block defines where your service will be deployed
provider:
  name: aws
  runtime: nodejs6.10

# The `functions` block defines what code to deploy
functions:
  helloWorld:
    handler: handler.helloWorld
    # The `events` block defines how to trigger the handler.helloWorld code
    events:
      - http:
          path: hello-world
          method: get
          cors: true


To define a rest endpoint we have to mention the method (get or post) and path inside events -> http.
cors: true will enable the cross.

To know more about it please visit the serverless.com (https://serverless.com/framework/docs/providers/aws/guide/events/)


If you want to push the same code to your aws environment then run the following command.


$sls deploy

Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (967 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..............
Serverless: Stack update finished...
Service Information
service: serverless-hello-world
stage: dev
region: us-east-1
api keys:
  None
endpoints:
  GET - https://l2krwp3ete.execute-api.us-east-1.amazonaws.com/dev/hello-world
functions:
  helloWorld: serverless-hello-world-dev-helloWorld


- Go to the browser and enter the GET endpoint URL. Your's will be different than mine. Mine is for testing purpose. It wont be available for you.

- You can see the event object that lamda return as a response in the browser.


* For more information please visit the following link.
https://aws.amazon.com/lambda/details/
https://serverless.com/framework/docs/providers/aws/guide/quick-start/


Create your first nodejs lamda function using serverless framework

AWS Lamda :

If you are not aware of lamda function, please visit the following link to know about it.

http://www.fullstacktechnos.com/2017/11/what-is-aws-lamda.html


Serverless Framework :

https://serverless.com/

Serverless framework is the toolkit for deploying and operating serverless architectures. The framework can manage deploying infrastructure and code to AWS, Google Cloud Platofrm, Microsoft Azure and IBM Openwhisk.
If you want to launch your first lamda function to cloud then this framework will definitely help you.

Serverless Setup for Lamda

1) Install nodejs: (Node.js v6.5.0 or later is required)


$node -v
v6.11.3


2) Install serverless framework CLI.


npm install -g serverless

$serverless -v
1.18.1


3) Install AWS-CLI.


$aws --version
aws-cli/1.11.127 Python/3.6.2 Darwin/17.2.0 botocore/1.5.90

If you need any help to install AWS-CLI please refer the following article.
http://www.fullstacktechnos.com/2017/07/how-to-install-aws-cli-in-mac.html


3) Create AWS Admin user and get the keys.

To manage the aws resource serverless needs AWS account credentials which has the required roles and permissions to manage the aws infrastructure. If you don't have a AWS account create a free one.

- Create an user having administrator access (which i think easy to test) and get the access key and secret key for that user.

Note:
Please follow the following article to know how to create aws user and how to add specific roles.

http://www.fullstacktechnos.com/2017/07/how-to-push-local-file-to-s3-using-aws.html

Don't worry about the name of the article. It gives you the information about how to add an aws user,  specific role and how to access the keys.


4) Configure credentials using aws-cli.

Go to the console and type


$ aws configure
AWS Access Key ID [****************]:
AWS Secret Access Key [****************]:
Default region name [None]:
Default output format [None]:


5) Create a nodejs project using npm

Go to the console, create folder called test-lamda, go inside and type "npm init". Follow the instructions.


6) Create a lamda function using serverless

Go to console, Inside your nodejs project folder type



$serverless create --template aws-nodejs

Serverless: Generating boilerplate...
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.18.1
 -------'

Serverless: Successfully generated boilerplate for template: "aws-nodejs"

Serverless: NOTE: Please update the "service" property in serverless.yml with your service name



Please check the handler.js and serverless.yml file.


handler.js :

It has a single lamda function called "hello" which has 3 input parameters i)event ii) context iii)callback

event contains the req object that has information about path, httpMethod, headers etc.
This basic lamda function when invoked will create a response object and send it back.


serverless.yml:

This file has all the aws infrastructure details that serverless needs to configure when enabled. You can see only service and provider is enabled. You can enable any other features as per requirement



7) Deploy your lamda function to AWS

Go to console, Inside your nodejs project folder type.


$serverless deploy

Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (1.29 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...............
Serverless: Stack update finished...
Service Information
service: test-lamda-serverless
stage: dev
region: us-east-1
stack: test-lamda-serverless-dev
api keys:
  None
endpoints:
  None
functions:
  hello: test-lamda-serverless-dev-hello



8) Invoke your lamda function


$sls invoke --function hello
{
    "statusCode": 200,
    "body": "{\"message\":\"Go Serverless v1.0! Your function executed successfully!\",\"input\":{}}"

}

* sls is short form of serverless


9) Check the logs.


$sls logs -f hello -t

START RequestId: 3cc05fc9-cee9-11e8-a9ca-f960d9ae7ppp Version: $LATEST
END RequestId: 3cc05fc9-cee9-11e8-a9ca-f960d9ae7ppp

REPORT RequestId: 3cc05fc9-cee9-11e8-a9ca-f960d9ae7ppp  Duration: 0.83 ms       Billed Duration: 100 ms         Memory Size: 1024 MB    Max Memory Used: 20 MB

* f is short form of function, hello is the function name

Summary:

1) nodejs v6.5.0 or later
2) npm install -g serverless
3) aws configure <Configure aws admin account access key and secret>
4) npm init
5) serverless create --template aws-nodejs
6) serverless deploy
7) sls invoke --function hello


* For more details on serverless framework for aws please visit following links:

https://serverless.com/framework/docs/providers/aws/guide/quick-start/
https://serverless.com/framework/docs/providers/aws/guide/credentials/
https://serverless.com/framework/docs/providers/aws/examples/hello-world/node/


What is AWS Lamda ?

AWS Lambda is a serverless compute service that runs the code in response to events.
For ex: When a image is uploaded to Amazon s3 bucket a lamda function can be triggered and resize the image and store it back. Lamda can respond to HTTP request via Amazon API Gateway. One can move their backend code that is being served from nodejs or any other app server to lamda.


Where lamda code runs ?

Lamda code runs on the server manages by AWS.
AWS automatically manages the underlying compute resources. It manages all the server management, provisioning, scaling, performance, security, monitoring, logging etc. So user does not need to worry about anything other than writing the code.


What is Serverless ?

You must have already got the answer by now. We don't need to provision any server while running our lamda code. That does not mean there is no server. Its there but we can not see it. Amazon will manage the server for us. We need to write the code, put it in lamda and AWS will take care of the rest. The server is kind of hidden from us so we call it serverless.


What is lamda function ?

The code we run on AWS Lambda is called a “Lambda function.” Once it is ready it is always available. These functions are stateless. They should ideally perform a unit of work. Each Lambda function runs in an isolated computing environment with its own resources. I would say these are nano service which can group together to create micro-service or itself can be called mico-service
AWS will invoke copy of as many lamda function as it needs to respond to incoming events. This way AWS manages scale and performance.


What are the languages that lamda supports ?

At this point we can write our code in nodejs, java, python and C#. Lamda has support for 3rd party libs and native libs.


How much we need to pay for the lamda service ?

We need to pay only for the compute time of the server. The server will not run for ever. It will be invoked only when there is an incoming event to the lamda.


For more information :
https://aws.amazon.com/lambda/details/

Sunday, November 19, 2017

How to start your Angular 4 project ?


What is Angular 4 ?

- AngularJS came on 2010 and Angular 2 came on mid 2016 with complete rewritten of framework in Typescript.
- Angular 4 is a version match not a upgrade to Angular 2.
- Angular 4 is just called Angular.

Create Angular 4 Project :

Setup :

1) node and npm should be installed. (https://nodejs.org/en/)

- If you already installed node and wants to update please check the following link. (Its for Mac)
http://www.fullstacktechnos.com/2017/09/how-to-update-nodejs-in-mac.html

$ node -v
v6.11.3

2) Install angular CLI

$ npm install -g @angular/cli
...

$ ng -v
….
@angular/cli: 1.4.4
node: 6.11.3
os: darwin x64


Use angular CLI to create a new hello-world project


$ ng new hellow-world
installing ng
  create .editorconfig
 …..
……
  create tslint.json
Installing packages for tooling via npm.
Installed packages for tooling via npm.
Successfully initialized git.
Project 'hellow-world' successfully created.


Install Visual Studio Code : (https://code.visualstudio.com/)
Open the editor and type Shift + Command + P (from Mac)

Search for 'Path', and Install

Go inside the project folder and type "code ."
It will open the project folder in VS Code editor or you can open the project folder directly from editor.


Project folder structure will look like the below.





Serve the Angular Code

hellow-world $ ng serve
** NG Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200 **
Date: 2017-09-07T15:35:06.229Z                                                          
Hash: c2e3ddcf0d5dd2646b8f
Time: 8944ms
chunk {inline} inline.bundle.js, inline.bundle.js.map (inline) 5.83 kB [entry] [rendered]
chunk {main} main.bundle.js, main.bundle.js.map (main) 8.44 kB {vendor} [initial] [rendered]
chunk {polyfills} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 209 kB {inline} [initial] [rendered]
chunk {styles} styles.bundle.js, styles.bundle.js.map (styles) 11.3 kB {inline} [initial] [rendered]
chunk {vendor} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.27 MB [initial] [rendered]


webpack: Compiled successfully.


visit localhost:4200 in browser







Entry Point:

main.ts -> platformBrowserDynamic().bootstrapModule(AppModule);


Minor Modification :

- Go to app.component.ts and change,

export class AppComponent {
  title = 'My first Angular app';
}


- Check the command prompt : 

web pack which is integrated build tool with angular cli compiled and created few bundle.js files and browser being refreshed automatically with the new content.

Note:
Before you start writing code for your angular project, please get a basic understanding of typescript. If you are already familiar ignore the following article.

http://www.fullstacktechnos.com/2017/09/typescript-fundamentals.html

Sunday, October 29, 2017

Firebase Real Time Database for Web App

1) Create a Firebase project

- Create a firebase Project at https://console.firebase.google.com
- Go to Project Overview -> Click "Add firebase to your webapp"
- It will open a popup and you will find apikeys and endpoints as per your project settings.
- You will use this data in your frontend html file that will connect to firebase.
- Go to Database -> Rules and update the content as following

{
  "rules": {
    ".read": true,
    ".write": true
  }
}

This will allow anyone to read and write to the database. Its only for testing purpose. In actual production app you can see more complicated rules. You must not do this for your production app.

2) Checkout the following frontend demo app from github.

https://github.com/fullstacktechnos/firebase-frontend

- I am using node.js as local server to serve the page. If you want to use node.js then please check the following article:

http://www.fullstacktechnos.com/2017/10/serving-static-file-using-nodejs-and.html

- I have a single page called index.html and a config file called firebaseconf.js inside public. Config file has all dummy data. You have to replace with your actual project configs.
- Open the firebaseconf.js inside public folder.
- Add the firebase initialization code.

  // Initialize Firebase
  var config = {
    apiKey: "bjfuawfbajbawfbawawfbfawbbawflf",
    authDomain: "testproject.firebaseapp.com",
    databaseURL: "https://testproject.firebaseio.com",
    projectId: "testproject",
    storageBucket: "testproject.appspot.com",
    messagingSenderId: "123456789123"
  };
  firebase.initializeApp(config);

* I have added all dummy data. Please use the actual data in your project.  

- Open the index.html and check the following code.

Send data to Firebase

                             //Send data to DB
            $("#sendmsg").click(function() {
                var content = $("#content").val();
                if (!content) {
                    return console.log('No content');
                }
                $("li").remove();
                var ref = firebase.database().ref('messages');
                var data = {
                    type: 'Generic',
                    description: content
                }
                ref.push(data);
            });


- In the above piece of code I am getting the message text from the html element (with id 'content') and sending it to the firebase when user clicks on the button (with id 'sendmsg'). Check the elements in the index.html.
- firebase.database().ref('messages') will get the database reference. Create the payload and send it to the firebase realtime db with ref.push(payload).

- Once message sent successfully go to firebase console. https://console.firebase.google.com
- Inside your project, go to Database.
- Check the messages.
- You will find the new message inside uid with your given content in description.


Getting data from Firebase

- You need to listen to the database event in your frontend webapp to get db updates.
- Check the following code.

                            //Read Data
            var ref = firebase.database().ref('messages');
            ref.on('value',function(result) {
                var messages = result.val();
                if (messages) {
                    $("li").remove();
                    keys = Object.keys(messages)
                    keys.forEach(function(key) {
                    console.log('Type :' + messages[key].type + ' :: Content :' +  messages[key].description);
                    $("#messagelist").append('<li class="singlemsg">' + messages[key].description + '</li>');
                    });
                }
            }, 
            function(error) {
                console.log(error);
            });


* If you have not checked out the code from git then please don't worry about dom manipulation code written above. Just ignore them.


- Get the reference of the database and call ref.on. It will be invoked whenever there is a db insert or update on messages. Get the result and show to the user.
- You can notice as soon as you send the message to firebase it will be displayed in the page.


Note :

For more info please visit firebase official documentation link given below.
https://firebase.google.com/docs/database/web/start

To know more about firebase and cloud functions please find the below articles:
1) http://www.fullstacktechnos.com/2017/10/firebase-authentication-service-for-web.html
2) http://www.fullstacktechnos.com/2017/10/why-we-need-firebase-cloud-functions.html
3) http://www.fullstacktechnos.com/2017/10/introduction-to-cloud-functions-for.html

Saturday, October 21, 2017

Firebase authentication service for web app

To understand firebase authentication service, lets create a simple frontend web app which will talk to firebase.

1) Create Firebase project

- Create a firebase Project at https://console.firebase.google.com.
- Go to Project Overview -> Click "Add firebase to your webapp"
- It will open a popup and you will find apikeys and endpoints as per your project settings.
- You will use this data in your frontend html file that will connect to firebase.

2) Enable Sign-In Method from Authentication

- You are inside your project in https://console.firebase.google.com.
- Go to Authentication tab from left side menu.
- Click on the SignIn Method. You will be seeing all the supported methods like Email/Password, Phone, Google, Facebook, Twitter etc.
- Enable Email/Password and Google.

3) Create frontend webapp

- You can download the project from the git from the below location or you can use your own.

https://github.com/fullstacktechnos/firebase-frontend


- I am using node.js as local server to serve the page. If you want to use node.js then please check the following article:


http://www.fullstacktechnos.com/2017/10/serving-static-file-using-nodejs-and.html


- I have a single page called index.html and a config file called firebaseconf.js inside public. Config file has all dummy data. You have to replace with your actual project configs. I am using jquery to access dom element.

- Open the firebaseconf.js inside public folder.
- Add the firebase initialization code.


  // Initialize Firebase
  var config = {
    apiKey: "bjfuawfbajbawfbawawfbfawbbawflf",
    authDomain: "testproject.firebaseapp.com",
    databaseURL: "https://testproject.firebaseio.com",
    projectId: "testproject",
    storageBucket: "testproject.appspot.com",
    messagingSenderId: "123456789123"
  };
  firebase.initializeApp(config);


Go to the index.html. I have already created the elements and added event listener to call to firebase. However if you want to create your own please follow the steps below.

- Create email and password field and 4 buttons. Signin, Register, Signin With Google, Signout
- Add event listener for all the buttons.
- Call the firebase authentication service for respective actions.
- Google service will handle all the error conditions. You don't need to worry about it. Check the console after each event.


User Registration:

- At the time of user registration, get the email and password and call the firebase auth service createUserWithEmailAndPassword. 
- If the email is already in use, try logging in using google signin. Google signin code is mentioned below in the article.
- Once the user is created successfully you can find it in firebase console. 
- Go to your project inside https://console.firebase.google.com
- Go to "Authentication" -> "Users"
- You can find the newly created user details.
- You can also add/delete user account from the firebase console.



                              $("#register").click(function(e) {
                var email = $("#email").val();
                var password = $("#password").val();
                if (!email || !password) {
                    return console.log('email and password is required');
                }
                firebase.auth().createUserWithEmailAndPassword(email, password)
                .then(function(result) {
                    console.log(result);
                })
                .catch(function(error){
                    // If user is already registered with the same email
                    // then try to login using google signin
                    if (error.code === 'auth/email-already-in-use') {
                        var credential = firebase.auth.EmailAuthProvider.credential(email, password);
                        var provider = new firebase.auth.GoogleAuthProvider();
                        firebase.auth().signInWithPopup(provider)
                        .then(function(result) {
                            console.log(result); 
                        })
                        .catch(function(error1) {
                            console.log('Google sign in error', error1);
                        });
                    }
                })
            });



User Signin :

- At the time of user login, get the email and password and call the firebase auth service signInWithEmailAndPassword. 
- Test with email that is not present in firebase. 


                          $("#signin").click(function(e) {
                var email = $("#email").val();
                var password = $("#password").val();
                if (!email || !password) {
                    return console.log('email and password is required');
                }
                firebase.auth().signInWithEmailAndPassword(email, password)
                .then(function(result) {
                    console.log(result);
                })
                .catch(function(error) {
                    console.log('signIn error', error);
                })
            });


Google Signin :

- It will work if the page is served from a server.
- If you directly open the index.html or your static file in browser it may not work. So better you use any static server to host the page. I am using node.js for it.
- Get the auth provider and use it to call the service. 
- I am using popup window to enter the google credentials so calling signInWithPopup(). 
- You can even use signInWithRedirect()


                            $("#gsignin").click(function(){
                $("#message").text("");
                // Sign in with Google
                var provider = new firebase.auth.GoogleAuthProvider();
                provider.addScope('profile');
                provider.addScope('email');
                return firebase.auth().signInWithPopup(provider)
                    .then(function(result) {
                        console.log(result); 
                    })
                    .catch(function(error) {
                        console.log('Google sign in error', error);
                    });
            });


User Signout :

Call the auth signOut() function.

                $("#signout").click(function() {
                firebase.auth().signOut();
            });


Listening to Auth State :

- Place the following code once the document is loaded. Its not part of any button event listener.
- It will write the user object data to console for debugging purpose every time there is a change in authentication state like user registration, login, signout etc.

           firebase.auth().onAuthStateChanged(function(user) {
                console.log('user', user);
            });



Note :

For more info please visit firebase official documentation link given below.

https://firebase.google.com/docs/auth/web/start


To know more about firebase and cloud functions please find the below articles:

1) http://www.fullstacktechnos.com/2017/10/why-we-need-firebase-cloud-functions.html

2) http://www.fullstacktechnos.com/2017/10/introduction-to-cloud-functions-for.html