Categories
Fastify

Server-Side Development with Fastify — Fluent Schema Request Validation

Spread the love

Fastify is a small Node framework for developing back end web apps.

In this article, we’ll look at how to create back end apps with Fastify.

Fluent Schema

We can set up a schema to validate request content with the fluent-schema module in our Fastify app.

For example, we can write:

const fastify = require('fastify')({})
const S = require('fluent-schema')

const MY_KEYS = {
  KEY1: 'ONE',
  KEY2: 'TWO'
}

const bodyJsonSchema = S.object()
  .prop('someKey', S.string())
  .prop('someOtherKey', S.number())
  .prop('requiredKey', S.array().maxItems(3).items(S.integer()).required())
  .prop('nullableKey', S.mixed([S.TYPES.NUMBER, S.TYPES.NULL]))
  .prop('multipleTypesKey', S.mixed([S.TYPES.BOOLEAN, S.TYPES.NUMBER]))
  .prop('multipleRestrictedTypesKey', S.oneOf([S.string().maxLength(5), S.number().minimum(10)]))
  .prop('enumKey', S.enum(Object.values(MY_KEYS)))
  .prop('notTypeKey', S.not(S.array()))

const queryStringJsonSchema = S.object()
  .prop('name', S.string())
  .prop('excitement', S.integer())

const paramsJsonSchema = S.object()
  .prop('par1', S.string())
  .prop('par2', S.integer())

const headersJsonSchema = S.object()
  .prop('x-foo', S.string().required())

const schema = {
  body: bodyJsonSchema,
  querystring: queryStringJsonSchema,
  params: paramsJsonSchema,
  headers: headersJsonSchema
}

fastify.post('/', { schema }, function (req, reply) {
  reply.send('success')
})
const start = async () => {
  try {
    await fastify.listen(3000, '0.0.0.0')
  } catch (err) {
    fastify.log.error(err)
    process.exit(1)
  }
}
start()

We add the bodyJsonSchema to validate the request body.

S.object is called to let us validate objects.

prop is used to validate properties. It takes the property name as the first argument.

S.string indicates that it’s a string.

S.array validates that a property is an array.

maxItems validates the max number of items in an array.

S.oneOf lets us specify one of multiple types for a property.

S.enum validates a property is an enum. It takes a string array with the enum values.

We can also specify validation schemas for query strings, URL parameters, and headers with fluent-schema .

Now when we make a request with content that doesn’t match the schema, we’ll get an error.

Schema Reuse

We can reuse our schemas by adding an ID to them with the id method.

For instance, we can write:

const fastify = require('fastify')({})
const S = require('fluent-schema')

const addressSchema = S.object()
  .id('#address')
  .prop('line1').required()
  .prop('line2')
  .prop('country').required()
  .prop('city').required()
  .prop('zip').required()

const commonSchemas = S.object()
  .id('app')
  .definition('addressSchema', addressSchema)

fastify.addSchema(commonSchemas)

const bodyJsonSchema = S.object()
  .prop('home', S.ref('app#address')).required()
  .prop('office', S.ref('app#/definitions/addressSchema')).required()

const schema = { body: bodyJsonSchema }

fastify.post('/', { schema }, function (req, reply) {
  reply.send('success')
})
const start = async () => {
  try {
    await fastify.listen(3000, '0.0.0.0')
  } catch (err) {
    fastify.log.error(err)
    process.exit(1)
  }
}
start()

to create our schemas with the addressSchema .

Then we add the definition to a reusable schema with the definition method.

id specifies the ID of the schema.

S.ref lets us reference a schema in the code by its ID so we can reuse them.

Then we create the schema object and pass it to the 2nd argument of post .

We can also create the schema with an object:

const fastify = require('fastify')({})

const sharedAddressSchema = {
  $id: 'sharedAddress',
  type: 'object',
  required: ['line1', 'country', 'city', 'zip'],
  properties: {
    line1: { type: 'string' },
    line2: { type: 'string' },
    country: { type: 'string' },
    city: { type: 'string' },
    zip: { type: 'string' }
  }
}

fastify.addSchema(sharedAddressSchema)

const bodyJsonSchema = {
  type: 'object',
  properties: {
    vacation: 'sharedAddress#'
  }
}

const schema = { body: bodyJsonSchema }

fastify.post('/', { schema }, function(req, reply) {
  reply.send('success')
})

const start = async () => {
  try {
    await fastify.listen(3000, '0.0.0.0')
  } catch (err) {
    fastify.log.error(err)
    process.exit(1)
  }
}
start()

We create an object for the schema.

Then we all fastify.addSchema to add the schema.

And then we create the schema object with the added schema which references the schema by the $id property.

And then we add the schema to the route handler.

Conclusion

We can add validation for requests with the fluent-schema library to our Fastify app.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *