@volcanicminds/backend relies heavily on Fastify’s JSON Schema validation and serialization. The framework provides default schemas for core features like Authentication (Login, Registration), but real-world applications often need to extend these schemas to include custom data fields (e.g., firstName, company, roles).
Instead of modifying the framework source code, you can use the built-in Schema Overriding mechanism.
The Schema Loader (lib/loader/schemas.ts) follows a specific loading order:
lib/schemas directory.src/schemas directory.$id as a Base Schema, the framework performs a Smart Deep Merge using lodash.defaultsDeep.Rule: Your custom schema properties take precedence or are added to the base definition.
Scenario: You want the /auth/login endpoint to return the user’s firstName, lastName, and professional profile data, in addition to the standard JWT token.
Look at the framework documentation or source code to find the $id of the schema you want to extend. For login responses, it is authLoginResponseSchema.
Base Schema (Framework):
// lib/schemas/auth.ts
export const authLoginResponseSchema = {
$id: 'authLoginResponseSchema',
type: 'object',
properties: {
id: { type: 'string' },
username: { type: 'string' },
email: { type: 'string' },
token: { type: 'string' }
// ... other standard fields
}
}
In your project, create a schema file (e.g., src/schemas/user.ts) and define an object with the exact same $id. Define only the fields you want to add or modify.
Custom Schema (Application):
// src/schemas/user.ts
// This defines the structure of the Professional entity referenced below
export const professionalSchema = {
$id: 'professionalSchema',
type: 'object',
properties: {
id: { type: 'string' },
firstName: { type: 'string' },
company: { type: 'string' }
}
}
// This overrides the core authLoginResponseSchema
export const authLoginResponseSchema = {
$id: 'authLoginResponseSchema',
type: 'object',
nullable: true,
properties: {
// New fields to inject into the login response
firstName: { type: 'string' },
lastName: { type: 'string' },
// Complex objects can be referenced
professional: {
$ref: 'professionalSchema#'
}
}
}
When the server starts, it merges the two definitions. The effective schema used by Fastify for the /auth/login route will be:
{
$id: 'authLoginResponseSchema',
type: 'object',
properties: {
id: { type: 'string' }, // From Base
username: { type: 'string' }, // From Base
token: { type: 'string' }, // From Base
firstName: { type: 'string' }, // From Override
lastName: { type: 'string' }, // From Override
professional: { $ref: 'professionalSchema#' } // From Override
}
}
$ids.additionalProperties: true: While it allows any data to pass through, it disables Fastify’s serialization optimizations and weakens API contracts. Always define your fields explicitly in the override.required arrays. If you add a new field that must be present, add it to the required array in your custom schema.