Build a serverless app with the first serverless database

FaunaDB is the first truly serverless database. In this post, I’ll use the Serverless Framework to connect an AWS Lambda application with FaunaDB Serverless Cloud.

When I say serverless, I’m referring to the function-as-a-service pattern. A serverless system must scale dynamically per request, and not require any capacity planning or provisioning. For instance, you can connect to FaunaDB in moments, and scale seamlessly from prototype to runaway hit.

A serverless system must scale dynamically per request.

Current popular cloud databases do not support this level of elasticity—you have to pay for capacity you don’t use. Additionally, they often lack support for joins, indexes, authentication, and other capabilities necessary to build a rich application.

What is FaunaDB?

FaunaDB Serverless Cloud is a globally distributed database that requires no provisioning. Capacity is metered and available on demand—you only pay for what you use. In addition, you can always port your application to FaunaDB On-Premises in your own datacenter or private cloud, eliminating cloud infrastructure lock-in.

FaunaDB is a globally distributed database that requires no provisioning—you only pay for what you use.

FaunaDB is a perfect fit for serverless development. Let’s code.

Getting started with Serverless Framework

Serverless is leading the serverless framework market right now with a clean system for configuring, writing, and deploying serverless application code to different cloud infrastructure providers. I took an afternoon to port one of their storage examples from DynamoDB to FaunaDB. It was incredibly easy to accomplish. Looking through this code will show us how simple it is to set up a serverless environment.

The CRUD service I am porting is a simple REST API that allows the creation, updating, and deletion of todo items, as well as listing all todo times. It’s a toy example, so after we look through the code, I’ll describe how you’d go about adding a multi-list multi-user data model where users can invite other members to read and update todo lists. It would be a lot more productive to push that logic to FaunaDB, but in this example I am limited by the capabilities DynamoDB also provides.

The README contains installation and usage instructions, and you can go here to get instant access to FaunaDB.

Once you have this set up running, you can play around with FaunaDB’s more interesting features, like implementing a social graph. Check out this social graph tutorial.

Defining the functions

The first file to start reading any app using the Serverless Framework is serverless.yml which defines the service and links functions to event handlers.

readAll example

In ours we can see the function definitions; here’s one of them:

functions:
  readAll:
    handler: handler.readAll
    events:
      - http:
          path: todos
          method: get
          cors: true

This configuration means the readAll function in handler.js will be called when an HTTP GET is received at the todos path. If you look through the configuration you’ll see all the functions are linked to handler.js, so that’s where I’ll look next.

module.exports.readAll = (event, context, callback) => {
  todosReadAll(event, (error, result) => {
    const response = {
      statusCode: 200,
      headers: {
        "Access-Control-Allow-Origin" : "*"
      },
      body: JSON.stringify(result),
    };

    context.succeed(response);
  });
};

Everything in handler.js is concerned with managing HTTP, so the actual logic is imported from a module for each function. In this case, todos-read-all.js. We’ll include the entire file here because this is the place FaunaDB comes into play.

'use strict';

const faunadb = require('faunadb');
const q = faunadb.query;
const client = new faunadb.Client({
  secret: process.env.FAUNADB_SECRET
});

module.exports = (event, callback) => {
  return client.query(q.Paginate(q.Match(q.Ref("indexes/all_todos"))))
  .then((response) => {
    callback(false, response);
  }).catch((error) => {
    callback(error)
  })
};

In this case I’ll run a query for all todos, using a FaunaDB secret passed via configuration in serverless.yml. FaunaDB uses HTTP for queries so you don’t need to worry about sharing connections between modules or invocations.

Differences between FaunaDB and DynamoDB interfaces

The main difference between the DynamoDB and the FaunaDB versions is that this:

return dynamoDb.scan({TableName: 'todos'}, (error, data) => { … })

becomes:

return client.query(q.Paginate(q.Match(q.Ref("indexes/all_todos"))))

Try it out

Follow the README instructions to launch and run the service, then create a few todo items.

Now you’re ready to explore your data and experiment with queries in the FaunaDB dashboard. Open the dashboard via this sign up form. It will look something like this:

FaunaDB Dashboard Screenshot

If you look closely at the screenshot you get a hint at FaunaDB’s temporal capabilities which can power everything from social activity feeds, to auditing, to mobile sync.

Moving beyond a demo

In a production-worthy version of this application, the request would contain a list ID, and our query would validate that the list is visible to the user, before returning just the matching items. This security model is similar to collaboration apps you may be familiar with, and it’s supported natively by FaunaDB.

The source DynamoDB example lists all todos using a scan operation. To move to a secure list sharing model in DynamoDB, you would have to add an index and then run multiple queries from your serverless handler to validate that the list is visible to the requesting user.

To build a real application with FaunaDB, you’d also create an index on list ID, but you’d be able to pass authentication credentials into the database with your query. Instead of requiring multiple calls, FaunaDB will return data you need in a single query, including list items and metadata. Watch this blog for an updated serverless application with a more mature multi-user data model using FaunaDB’s security features.

Conclusion

As I build more examples using a serverless architecture, I’ll choose the Serverless.com framework again. You can look forward to an example of serverless code dynamically provisioning resource using FauanDB’s multi-tenant QoS features, and how to integrate FaunaDB with other serverless components.

Over time, which do you think provides better agility: a database that requires rethinking your data layout when requirements change, and implementing big pieces of policy in application code—or a database with flexible queries and security awareness? I hope you agree that the answer is FaunaDB.

Begin Today

FaunaDB is in production today serving tens of millions of users. Start your free trial of FaunaDB Serverless Cloud and experience the power of global consistency.