Build a QR code generator


Overview

This tutorial is going to help you deploy a serverless function that can generate a QR code. We're gonna use Firebase cloud functions and hosting for this project. I am going to assume that you have basic JavaScript knowledge and an idea of how serverless architecture works. If you don't have both don't worry, I just deployed my first function a few days ago too. Check out the deployed application here

Confession

I was following the tutorial on Cloudflare Workers but I needed their paid plan to deploy a website with a frontend and that's how I ended up with Firebase cloud functions.

Okay so before we start coding, there's a question that most of you have (Assuming people read my blog lol!)

What is Serverless?

Usually, when you write code for the backend, you have to manage the servers, worry about scaling, pay for the entire hosting. Enter the world of serverless computing, in serverless architecture you only need to write the required code for your requests. It is a scalable and efficient way to develop applications such that you only pay for the resources you use and not pay for the entire hosting.

Function as a Service

Function as a service is a type of serverless computing where you write logic as functions. Each event triggers a function which then returns the required response, these functions are only executed when in need. Some of the widely used FaaS include AWS Lambda, Google Cloud Functions, Microsoft Azure Functions, and Cloudflare Workers.

Let's start coding!

First let's install the Firebase CLI, then login to firebase

npm install -g firebase-tools
firebase login

Now create a new directory named qrcode and run

firebase init

Select the functions and hosting options and create a new project with JavaScript as the language. Name your public directory as public itself and turn off the single page app feature. You should see the following directory structure after the initialisation

qrcode
├── firebase.json
├── functions
│   ├── index.js
│   ├── package.json
│   └── package-lock.json
└── public
    ├── 404.html
    └── index.html

Also before we start coding we need to change the nodejs version to 8 because firebase's free plan only supports node 8. This can be done by changing "node":"8" in package.json.

public/index.html

First let's just make a static HTML file, I just used bootstrap for styling here. So we have a page which accepts a text and sends it to an endpoint at /stringtoCode (spoiler alert this is where out function resides)

<!DOCTYPE html>
<html>
  <head>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta content="utf-8" http-equiv="encoding">
    <title>QR coder</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
     integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
    <style type="text/css">
      .top{
        margin-top: 10rem;
      }
    </style>
  </head>
  <body>
    <div class="container top">
      <h2>QR Coder</h2>
      <p>Paste the link or text you want to convert to a QR Code below</p>
    </div>

    <div class="container">
    <form name="qrText" method="GET" action="/stringtoCode">
  <div class="form-group">
    <label for="inputArea">Paste your text here</label>
    <input type="text" class="form-control" id="inputArea"  placeholder="Paste the text" name="text" required>
    <small id="emailHelp" class="form-text text-muted">Paste your link/text here.</small>
  </div>
  <button type="submit" class="btn btn-primary">Generate</button>
</form>
</div>
  </body>
</html>

QR Landing You should be able to see a page like the one above. Now we need to write the logic to convert the text recieved at endpoint /stringtoCode to a QR code.

functions/index.js

Now JavaScript time! But before we code, yeah you guessed it, time to install a dependency, head over to your terminal and go into the functions directory and

npm install qr-image

qr-image package helps us to convert text to qr-code (Yes there's a JavaScript package for everything). Now let's have a look at our function.

const functions = require('firebase-functions');
const qr = require('qr-image');

exports.stringtoCode = functions.https.onRequest( async(req, res) => {
	const text = req.query.text;
	const qr_image = qr.imageSync(text,{type:'svg',size:'10'});
	res.status(200).send(`
		<html>
		<head>
		<title>QR coder</title>
		<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" 
		integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
		<style type="text/css">
    		top{
      			 margin-top: 10rem;
     		}
     		.image{
     		 	margin-top:5rem;
     		}
    	</style>
		</head>
		<body>
	 	<div class="container top d-flex justify-content-center">
		<h1>Your QR Code</h1>
		</div>
		<div class='image d-flex justify-content-center'>
		${qr_image}
		<div>
		</body>
		</html>
	`);
});

First we load the modules firebase-functions and qr-image to variables functions and qr respectively then we create the function. stringtoCode is the name of our function and it handles HTTP events. This functions waits for a request event. We then extract the query text from the request using req.query.text this contains the text that we recieved at the endpoint /stringtoCode from the HTML form. Now that we have the required text we conver the text to an svg object using the imageSync method. We now have out QR code ready in the form of a SVG. Now we send the response back as an HTML string and diplay the svg object within it.

Yup it's as simple as that!

Now go back to the main directory and run the command below to test your project locally

firebase emulators:start

Head over to localhost:5000 and you can see the HTML page you created but you might notice that the form is not working! We'll get to why in a minute

Going to localhost:4000/functions we can see the endpoint of our function. You can test it out by passing a query to the url, if your endpoint is http://localhost:5001/qrcode-1212/us-central1/stringtoCode test it out by checking if http://localhost:5001/qrcode-1212/us-central1/stringtoCode?text="hello" generates a QR code. You should get a page like the one below.

QR image

Connecting everyting

So far we created an HTML page and a function that generates a QR code. The reason that the form does not work is that we have not told firebase where the deployed function should listen to when hosted along with a website. The function and the webpage are currently on two different ports. So how do we fix this? When we made our form we provided an attribute as action='/stringtoCode'. The endpoint /stringtoCode currently returns a 404 for our application. We should let firebase know that this endpoint should trigger the stringtoCode function in the functions/index.js file.

For this head towards the firebase.json file in the main directory and add a rewrites array, rewrites help us to serve a function from a hosting url. The file should now look like this.

{
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
     "rewrites": [ {
    "source": "/stringtoCode",
    "function": "stringtoCode"
  } ]
  }
}

Now your QR code generator app is fully functional. You can run the command below to deploy it to firebase.

firebase deploy

You can find the complete code for the project here