Building REST APIs with Fastify

  • Just how fast it is.
  • Reducing Overhead.
  • Fastify's plug-in based model.
  • Getting Started.

Introduction

  • General Purpose, low overhead web framework.
  • Very good for building fast HTTP APIs that use JSON as data format.
  • Extremely modular system based on plugins.

Reducing the overhead

Number of requests/sec to send a {"hello": world} as JSON response

Number of Requests/sec to send {"hello": world} as a JSON response

fast-json-stringify

  • Performant version of V8's JSON.stringify() function.
  • Used to double the throughput of the rendering of JSON.
  • Uses schemas and new Function () in a safe manner to outperform JSON.stringify().
const fastJSON = require('fast-json-stringify')

const schema = {
  // the object type we want to stringify
  type: 'object',

  // define all object properties
  properties: {
    username: {
      type: 'string'
    },
    fullName: {
      type: 'string'
    },
    age: {
      type: 'integer'
    }
  }
}

const stringify = fastJSON(schema)

console.log(stringify({
  username: 'johndoe',
  fullName: 'John Doe',
  age: 30
}))
{ "username": "johndoe", "fullName": "John Doe", "age": 30 }

find-my-way

Server Lifecycle

Fastify Plug-ins

  • Full encapsulation of plugins.
  • They can handle asynchronous code.
  • It guarantees load order and close order of plugins.

Registering Plug-ins

fastify.register(
  require('./my-plugin'),
  { options }
)
'use strict'
 
const fastify = require('fastify')()
 
fastify.get('/', function (req, reply) {
	reply.send({ hello: 'world' })
})
 
fastify.listen(3000)

Getting Started

Building a plugin to connect to MongoDb

const fastifyPlugin = require('fastify-plugin')
const MongoClient = require('mongodb').MongoClient

async function dbConnector (fastify, options) {
  const url = options.url
  delete options.url

  const db = await MongoClient.connect(url, options)
  fastify.decorate('mongo', db)
}

// Wrapping a plugin function with fastify-plugin exposes the decorators,
// hooks, and middlewares declared inside the plugin to the parent scope.
module.exports = fastifyPlugin(dbConnector)

Register the MongoDb Plug-in

'use strict'
 
const fastify = require('fastify')()

fastify.register(require('../plugins/mongodb'), {
	url: 'mongodb://localhost:27017/'
})

fastify.get('/', function (req, reply) {
	reply.send({ hello: 'world' })
})
 
fastify.listen(3000)

Declaring routes

let cartController = require('../controllers/cartController')

let routes = [
    {
        method: 'GET',
        url: '/api/user/:id/cart',
        handler: cartController.getCartForUser
    },
    {
        method: 'POST',
        url: '/api/user/:id/cart',
        handler: cartController.addItemToUserCart
    },
  ]

module.exports = routes;

Registering Routes

'use strict'
 
const fastify = require('fastify')()
const routes = require('./routes/index');

fastify.register(require('../plugins/mongodb'), {
	url: 'mongodb://localhost:27017/'
})

routes.forEach((route, index) => {
    fastify.log.info('>>New route registered: ', route.url, 'method: ', route.method);
    fastify.route(route);
});
 
fastify.listen(3000)

Writing route handlers

let cartController = {};

cartController.getCartForUser = async function  (request, reply) {
    const mongodb = this.db;
    const userId = request.params.id;

    const cart = await mongodb.collection('productCart').findOne({
        UserID: userId
    });

    reply.send(cart);
};
cartController.addItemToUserCart = async function  (request, reply) {
    const mongodb = this.db;
    const userId = request.params.id;
    const product = request.body.product;
    const filter = {UserID: userId};
    const newPrice = product.map(prod => prod.Price * prod.Quantity).reduce((acc, curr) => acc + curr);
    const update = {$set: {Product: product}, $inc: { TotalPrice: newPrice}};
    await mongodb.collection('productCart').findOneAndUpdate(filter, update, {upsert: true, useFindAndModify: true});
    let cart = await mongodb.collection('productCart').findOne({
        UserID: userId
    });
    reply.send(cart);
};


module.exports = cartController;

Thanks!

Made with Slides.com