Building a Serverless API in 10 Minutes

As a frontend engineer, most of my time is consumed in creating flashy UIs and generating frontend logic with either React or Angular. This is really fun in most cases but there comes a time where you need to really know about the server side stuff to deploy a full fledged application to production. This means that you have to upgrade yourself to be a full stack engineer, which is great, challenging and fun for most of us.

When writing server-side code, there are so many options available, Laravel, Rails, Django, Express etc. But it doesn’t end there. Say you develop an API using one of the above frameworks. You need to know how to deploy them into a server. Then you need to start worrying about server side configurations, containerizing your application etc etc and you are suddenly exploring uncharted waters if you are not much familiar with Devops technologies and tools.

Serverless technology is starting the put back smiles on our faces as frontend engineers. Now we can focus on the browser and rollout servers within 3 minutes.

Concept of being Serverless

“Server-less” is a coined term that refers to building web apps without bothering about how the server is set up. The term causes confusion to developers that are new to the concept. It doesn’t mean that your app won’t live on a server, rather it means that the sever setup and management is left out to be managed by the provisioning platform.

WebTask

Google Cloud Functions, Firebase Cloud Functions, Azure Cloud Functions, AWS Lambda, etc are all serverless platforms you can lay your hands. Webtask is yet another serverless platform which is seamlessly easy to get started with.

My choice for Webtask is greatly influenced on how easy it is to get started with less overwhelming docs.

Okay, Let’s get started!

Setting up Project

First of all, let’s first install the tools we need to get a simple hello world application running. For this you need to have NodeJS installed in your development machine as a pre requisite.

Okay, with everything installed and good to go, let’s install the CLI provided by webtask, so that we could deploy functions easily.

npm install -g wt-cli

To deploy functions, Webtask needs a way to identify you and your functions. Therefore, an account is needed. Head straight to the Webtask website and login. You will use your email to login to the CLI.

Run the following command to login via your CLI

wt init <YOUR-EMAIL>

Create your project directory anywhere on your machine, add an index.jsin the directory with the following content:

module.exports = function (cb) {
cb(null, 'Hello World');
}

Hit the URL logged in the console after running the following command on the directory to see your deployed app:

wt create index

There you go! Your first hello world app deployed and up and running in a server within like 5 seconds. Amazing isn’t it?

Now let’s build something interesting, A simple TODO App.

API Project Structure

|---middlwares
|------db.js
|---models
|------Todo.js
|---routes
|------todos.js
|---package.json
|---index.js

The pacakge.json contains the dependencies for this project as well as important scripts to run and bundle our project to be Webtask-ready:

{
"name": "wt-todo-api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "npm run create -- --watch",
"create": "wt create index --bundle"
},
"author": "",
"license": "MIT",
"dependencies": {
"body-parser": "^1.18.2",
"express": "^4.16.2",
"mongoose": "^4.13.8",
"webtask-tools": "^3.2.0"
}
}

Setting up Express with Webtask

Webtask integrates best with JavaScript. As you have seen, we just exported a function and an app was created. You might be wondering how you could bring in a different programming model to the scene.

Exporting functions is just one of the programming models supported by Webtask. It happens to be the most basic but that not withstanding, you can employ what works for you. In our case we want to use Express.

Webtask has a utility tool, webtask-tools, to help you bind your express app to a Webtask context. Therefore, rather than exporting a simple function, you can export an express app bound to Webtask using webtask-tools

index.js

var Express = require('express');
var Webtask = require('webtask-tools');
var bodyParser = require('body-parser')
var app = Express();

app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

// yet to be created
app.use(require('./middlewares/db').connectDisconnect);
require('./routes/todos')(app);

module.exports = Webtask.fromExpress(app);

If you are familiar with Express, you will see a lot of familiar codes. The big change is that rather than listening, we are exporting a function created from the Express app using webtask-tools.

The following lines are yet to be created which handles the app logic and the db connection.

...
app.use(require('./middlewares/db').connectDisconnect);
require('./routes/todos')(app);
...

Setting Up MongoDB with Mongolab

Mongolab by Object Labs is a good choice for cloud database because they eliminate the challenges of knowing how to setup a Cloud DB by just giving you a URL after choosing where you want your database to be hosted. To get started:

  • Quickly Sign up.
  • Create a database. A database URL will be supplied on the dashboard, copy and keep safe.
  • Create a user to authenticate the database. You can do this by clicking on the just created database, selecting the Users’ tab and clicking Add database user.

Mongoose Schema

Mongoose is a library that makes interacting with Mongo DB easier. It provides a more friendly API for connecting, creating, updating and querying your database. To do this, it uses a schemas to map Mongo collections and their properties to JavaScript object.

/models/Todo.js

 
const mongoose = require('mongoose');
module.exports = new mongoose.Schema({
owner: String,
description: String,
created_at: Date,
id: mongoose.Schema.ObjectId
})

Connection and Model

Next is to connect to a database and disconnect at the beginning and end of each request. To set this up, we need to use a middleware which will execute before each of our Express routes

/middlewares/db.js


var mongoose = require('mongoose');
// import Todo schema
const TodoSchema = require('../models/Todo')
module.exports = {
// Connect/Disconnect middleware
connectDisconnect: (req, res, next) => {
// Create connection using Mongo Lab URL
// available in Webtask context
const connection = mongoose.createConnection(req.webtaskContext.secrets.MONGO_URL);
// Create a mongoose model using the Schema
req.TodoModel = connection.model('Todo', TodoSchema);
req.on('end', () => {
// Disconnect when request
// processing is completed
mongoose.connection.close();
})
// Call next to move to
// the next Express middleware
next()
},
}

This middleware handles both connecting and disconnecting to a Mongolab database. The connection is achieved by passing a connection URL to the createConnection method. The URL is received via Webtask context which is explained in the next title.

When we establish a connection, we create a Mongoose model and attach the model to our request object.

We then attach an event listener to close the connection at the end of the request. next is called to pass down and continue with whatever middleware is next in the stack. This will most likely be an Express route.

Webtask Context

You can access contextual information via the Webtask context object. Such information can be used to store sensitive credentials like secrets, dynamic details like query strings, etc.

You can access the context via the function parameter:

module.exports = function(context, cb) {
cb(null, { hello: context.data.name || 'Anonymous' });
}

When using Express, you can access it from req.webtaskContext just like we saw in the database connection example. The MONGO_URL secret is passed in via the terminal while running the app:

wt create index --secret MONGO_URL=<MONGOLAB-CONNECTION-URL> --bundle

Express CRUD Routes

We have written all the helper codes our routes need to function. Tackling these routes is the next task

/routes/todos.js

 
var mongoose = require('mongoose');
const Todo = require('../models/Todo');
module.exports = (app) => {
app.get('/todos', (req, res) => {
req.TodoModel.find({}).sort({'created_at': -1}).exec((err, todos) => res.json(todos))
});
app.post('/todos', (req, res) => {
const newTodo = new req.TodoModel(Object.assign({}, req.body, {created_at: Date.now()}));
newTodo.save((err, savedTodo) => {
res.json(savedTodo)
})
})
app.put('/todos', (req, res) => {
const idParam = req.webtaskContext.query.id;
req.TodoModel.findOne({_id: idParam}, (err, todoToUpdate) => {
const updatedTodo = Object.assign(todoToUpdate, req.body);
updatedTodo.save((err, todo) => res.json(todo))
})
})
app.delete('/todos', (req, res) => {
const idParam = req.webtaskContext.query.id;
req.TodoModel.remove({_id: idParam}, (err, removedTodo) => res.json(removedTodo));
})
}
  • GET: /todos route uses mongoose to fetch all the todos stored in the database and sort them by date created in descending order
  • POST: /todos is used to create a new todo by storing the payload on req.body
  • PUT: /todos expects an id query string which it uses to find a todo and updates the todo based on the id
  • DELETE: /todos just like PUT, expects an id as well and removes an entry from the database collection based on the id

Deployment

That’s it. Now to deploy your application, you could simply enter the following command with the db connection URL provided by MongoLabs.

wt create index --secret MONGO_URL=<MONGOLAB-CONNECTION-URL> --bundle

Conclusion

After deployment, you can checkout your API routes with the application url logged in the console after the deployment and you can use a tool like Postman to test your API functionality.

On a closing note, I hope you enjoyed this tutorial and I will discuss how to integrate this API with a frontend application like Angular or React in the future. You can get the code from https://github.com/nilesh93/webtask-demo-api

Stay tuned and clap for more.

Like what you read? Give Nilesh Jayanandana a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.