Fastify
JaxNode January 2021
Fastify
- Alternative REST framework for Node.js
- Created to overcome shortcomings of Express
- Extremely fast
- Extendable
- Schema validation
- Logging
- TypeScript ready
Support
- Created by Matteo Collina and Tomas Della Vedova
- Sponsored by NearForm, OpenJS and Microsoft
- 19 contributors and maintainers
// Require the framework and instantiate it
const fastify = require('fastify')({ logger: true });
// Declare a route
fastify.get('/', async (request, reply) => {
return { hello: 'world' }
});
// Run the server!
const start = async () => {
try {
await fastify.listen(3000)
} catch (err) {
fastify.log.error(err)
process.exit(1)
}
}
start();
Validation Schema
schema: {
// request needs to have a querystring with a `name` parameter
querystring: {
name: { type: 'string' }
},
// the response needs to be an object with
// an `hello` property of type 'string'
response: {
200: {
type: 'object',
properties: {
hello: { type: 'string' }
}
}
}
}
Plugin Ecosystem
- fastify-swagger
- fastify-redis
- fastify-mongodb
- fastify-oauth2
- 42 core plugins, 124 community plugins
Feature | Express | Hapi | Fastify |
---|---|---|---|
router | ✔ | ✔ | ✔ |
middleware | ✔ | ❌ | ✔ |
plugins | ❌ | ✔ | ✔ |
validation | ❌ | ✔ | ✔ |
hooks | ❌ | ✔ | ✔ |
decorators | ❌ | ✔ | ✔ |
logging | ❌ | ✔ | ✔ |
async/await | ❌ | ✔ | ✔ |
req/sec | 18k | 20k | 36k |
Plugins
- fastify.register()
- pluginSignature(fastify, opts, done)
- Plugins over middleware is encouraged
// our-first-route.js
async function routes (fastify, options) {
fastify.get('/', async (request, reply) => {
return { hello: 'world' }
})
}
module.exports = routes
// server.js
const fastify = require('fastify')({
logger: true
})
fastify.register(require('./our-first-route'))
fastify.listen(3000, function (err, address) {
if (err) {
fastify.log.error(err)
process.exit(1)
}
fastify.log.info(`server listening on ${address}`)
})
Decorators
- Allows you to add properties and methods onto the fastify object
- Think Monkeypatching
- decorate(name, value, [dependencies])
// Decorate request with a 'user' property
fastify.decorateRequest('user', '')
// Update our property
fastify.addHook('preHandler', (req, reply, done) => {
req.user = 'Dave Growl'
done()
})
// And finally access it
fastify.get('/', (req, reply) => {
reply.send(`Hello, ${req.user}!`)
})
Routing
- 'DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT' and 'OPTIONS' all supported
- fastify.route()
- Support for express style short hand version
fastify.route({
method: 'GET',
url: '/',
schema: {
querystring: {
name: { type: 'string' },
excitement: { type: 'integer' }
},
response: {
200: {
type: 'object',
properties: {
hello: { type: 'string' }
}
}
}
},
handler: function (request, reply) {
reply.send({ hello: 'world' })
}
})
Routes long form
const opts = {
schema: {
response: {
200: {
type: 'object',
properties: {
hello: { type: 'string' }
}
}
}
}
}
fastify.get('/', opts, (request, reply) => {
reply.send({ hello: 'world' })
})
Long Form
Route Formats
- fastify.get('/example/:userId', (request, reply) => {})
- fastify.get('/example/*', (request, reply) => {}) // Wildcard
- fastify.get('/example/:file(^\\d+).png', (request, reply) => {})
Prefix
- Add option for prefix when registering the plugin
- fastify.register(require('./routes/v1/users'),
{ prefix: '/v1' })
- All routes will start with 'v1'
// server.js
const fastify = require('fastify')()
fastify.register(require('./routes/v1/users'), { prefix: '/v1' })
fastify.register(require('./routes/v2/users'), { prefix: '/v2' })
fastify.listen(3000)
// routes/v1/users.js
module.exports = function (fastify, opts, done) {
fastify.get('/user', handler_v1)
done()
}
// routes/v2/users.js
module.exports = function (fastify, opts, done) {
fastify.get('/user', handler_v2)
done()
}
Prefix Example
Templating
- point-of-view decorates reply with 'view' method
- Supported templating engines include 'marko', 'pug', 'ejs', 'handlebars', 'twig' and 'liquid'
- set by adding engine parameter when registering the plugin
fastify.register(require('point-of-view'), {
engine: {
ejs: require('ejs')
},
root: path.join(__dirname, 'view'),
layout: 'template',
viewExt: 'html', // it will add the extension to all the views
options: {}
})
Hooks
- Can inject code into different parts of the lifecycle
- Very useful for testing
- Request Hooks
- Application Hooks
onRequest
preParsing
preValidation
preHandler
preSerialization
onError
onSend
onResponse
onTimeout
onReady
onClose
onRoute
onRegister
Hook Types
fastify.addHook('preParsing', async (request, reply, payload) => {
// Some code
await asyncMethod()
return newPayload
})
Middleware
- Middleware was added for backwards compatibility
- Express middleware will run in Fastify
- Express support starting with 3.0.0
- Example would be Passport
- Can use 'middie' for improved performance
await fastify.register(require('fastify-express'))
fastify.use(require('cors')())
fastify.use(require('dns-prefetch-control')())
fastify.use(require('frameguard')())
fastify.use(require('hsts')())
fastify.use(require('ienoopen')())
fastify.use(require('x-xss-protection')())
Express Middleware Example
await fastify.register(require('middie'))
fastify.use(require('cors')())
middie example
Serverless
- Support for many serverless options
- aws-lambda
- netlify lambda
- Vercel
Demo
Questions?
Fastify
By David Fekke
Fastify
- 665