Building serverless web application with Angular 2, Webtask and Firebase

Recently I’ve been playing a lot with my pet project Tradux. It is a simple trading platform simulator which I built as an exercise in Redux, event sourcing and serverless architectures. I’ve decided to share some of the knowledge I learned in the form of this tutorial.

We’re going to build (guess what?) a TODO app. The client (in Angular 2) will be calling a Webtask whenever an event occurs (task created or task marked as done). The Webtask will update the data in the Firebase Database which will be then synchronized to the client.

Webtask is function-as-a-service offering which allows you to run pieces of code on demand, without having to worry about infrastructure, servers, etc. – i.e. serverless.

Architecture

The full source code is available on Github.

UPDATE: recently I gave a talk on this topic during #11 AngularJS Warsaw meetup. During the talk I built a silghtly different demo application which additionally performs spell checking in the webtask. Check out the Github repo for the source code.

Project skeleton

Let’s start with a very simple client in Angular 2. We will use Angular CLI to scaffold most of the code.

It takes a while for this command to run and it will install much more stuff than we need, but it’s still the quickest and most convenient way to go.

Let’s create a single component.

Now, let’s create the following directory structure. We’d like to share some code between the client and the webtask so we will put it in common directory.

Let’s start with defining the following interfaces inside model.ts. The first one is a command that will be sent from the client to the webtask. The second one is the entity representing an item on the list that will be stored in the database.

Finally, remember to add the Tasks component to app.component.html :

Adding Firebase to the Client

Before we proceed, you need to create a Firebase account. Firebase is a cloud platform which provides useful services for developing and deploying web and mobile applications. We will focus on one particular aspect of Firebase – the Realtime Database. The Realtime Database is a No-SQL storage mechanism which supports automatic synchronization of clients. In other words, when one of the clients modifies a record in the database, all other clients will see the changes (almost in real-time).

Once you created the account, let’s modify the database access rules. By default, the database only allows authenticated users. We will change it to allow anonymous reads. You can find the Rules tab once you click on the Database menu item.

Firebase provides a generous limit in the free Spark subscription. Create an account and define a new application. Once you are done, put the following definition in config.ts :

If you cannot find your settings, here is a helper for you. If you are really lazy, you can use the following settings, although I cannot guarantee any availability.

firebase2

Let’s now add Firebase to our client. There is an excellent library called AngularFire2 which we are going to use. Run the following commands:

Modify the imports section of AppModule  inside app.module.ts  so that it looks like this (you can import AngularFireModule  from angularfire2  module):

Now you can inject AngularFire object to Tasks component ( tasks.compontent.ts ):

You will also need some HTML to display tasks. I will include the form for adding tasks as well ( tasks.component.html ):

Our client is ready to display tasks, however there are no tasks in the database yet. Note how we can bind directly to  FirebaseListObservable – Firebase will take care of all the updates for us.

Creating the Webtask

Now we need to create the Webtask responsible for adding tasks to the list. Before we continue, please create an account on webtask.io. Again, you can use it for free for the purposes of this tutorial. The website will ask you to run the following commands:

Creating Webtasks is amazingly easy. You just need to define a function which takes a HTTP context and a callback to execute when the job is done. Paste the following code inside webtasks/add-task.ts :

The above snippet parses the request body (note how it uses the same AddTaskCommand  interface that the client). Later, it creates a Task  object and calls Firebase via the REST API to add the object to the collection. You could use the Firebase Javascript client instead of calling the REST API directly, however I couldn’t get it working in the Webtask environment.

Obviously in a production app you would perform validation here.

Note that you need to define the firebaseSecret  constant. You can find the private API key here:

zrzut-ekranu-2016-12-27-o-18-24-37

Firebase complains that this is a legacy method but it’s simply the quickest way to do that.

Why do we need to pass the secret now? That’s because we defined a database access rule which says that anonymous writes are not permitted. Using the secret key allows us to bypass the rule. Obviously, in a production app you would use some proper authentication.

We are ready to deploy the Webtask. A Webtask has to be a single JavaScript file. Ours is TypeScript and it depends on many other modules. Fortunately, Webtask.io provides a bundler which can do the hard work for us. Install it with the following command:

Now we can compile the TypeScript code to JavaScript, then run the bundler to create a single file and then deploy it using the Webtask CLI:

Voila, the Webtask is now in the wild. The CLI will tell you its URL. Copy it and paste inside config.ts:

Calling the Webtask from the Client

There is just one missing part – we need to call the Webtask from the client. Go to the Tasks component and add the below method:

This function is already linked to in HTML. Now, run the following command in console and enjoy the result!

Summary

In this short tutorial I showed how to quickly build a serverless web application using Webtasks. Honestly, you achieve the same result without the Webtasks and by talking directly to Firebase from the Client. However, having this additional layer allows you to perform complex validation or calculations. See Tradux for a nice example of a complex Webtask.

You can very easily use Firebase to deploy your app.

14 thoughts on “Building serverless web application with Angular 2, Webtask and Firebase

    1. It’s just for the purpose of this tutorial. You could do away without Webtask in the described scenario. However, it’s not hard to find a more complex scenario where you would for example need to do some validation that cannot be expressed with Firebase rules

  1. Are you kidding me? Firebase service must have lots of servers, so this app is not serverless. ╭(╯^╰)╮

  2. Would webtasks/add-task.ts rest in the client? I’m guessing no, since the inclusion of the Firebase secret would seem like a security leak…

  3. I am getting this error

    ERROR in ./src/app/tasks/tasks.component.ts
    Module build failed: Error: /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (18,3): Declaration or statement expected.)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (18,47): ‘(‘ expected.)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (20,22): ‘,’ expected.)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (20,26): ‘,’ expected.)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (20,45): ‘,’ expected.)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (20,60): ‘;’ expected.)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (18,10): Unused label.)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (18,17): Value of type ‘typeof FirebaseListObservable’ is not callable. Did you mean to include ‘new’?)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (20,3): Cannot find name ‘constructor’.)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (20,15): Cannot find name ‘public’.)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (20,22): Cannot find name ‘http’.)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (20,28): Cannot find name ‘Http’.)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (20,34): Cannot find name ‘angularFire’.)
    /Users/manojgoel/Projects/Angular/serverless-todo/src/app/tasks/tasks.component.ts (21,18): Cannot find name ‘angularFire’.)

    /code

    import { Component, OnInit } from ‘@angular/core’;
    2 import { AngularFire, FirebaseListObservable } from ‘angularfire2’;
    3 import { HttpModule } from ‘@angular/http’;
    4
    5 @Component({
    6 selector: ‘app-tasks’,
    7 templateUrl: ‘./tasks.component.html’,
    8 styleUrls: [‘./tasks.component.css’]
    9 })
    10 export class TasksComponent implements OnInit {
    11
    12 constructor() { }
    13
    14 ngOnInit() {
    15 }
    16
    17 }
    18 public tasks: FirebaseListObservable;
    19
    20 constructor(public http: Http, angularFire: AngularFire) {
    21 this.tasks = angularFire.database.list(‘tasks’);
    22 }
    23
    ~

  4. error ejecuting tsc add-task.ts
    “serverless-todo/src/common/config-secret.ts’ is not a module.”
    the file config-secret.ts : `firebaseSecret = “YnUMWkjkn5t6akhk…..”

Leave a Reply