Академический Документы
Профессиональный Документы
Культура Документы
inscrever-se
a8f79d3
5 dias atrás
16 colaboradores
Fastify
Validação e serialização
O Fastify usa uma abordagem baseada em esquema e, mesmo que não seja
obrigatório, recomendamos o uso do Esquema JSON para validar suas rotas e
serializar suas saídas. Internamente, o Fastify compila o esquema em uma função
de alto desempenho.
Validação
A validação de rota depende internamente do Ajv , que é um validador de esquema
JSON de alto desempenho. A validação da entrada é muito fácil: basta adicionar os
campos que você precisa dentro do esquema de rota e pronto! As validações
suportadas são:
Exemplo:
const bodyJsonSchema = {
type: 'object',
required: ['requiredKey'],
properties: {
someKey: { type: 'string' },
someOtherKey: { type: 'number' },
requiredKey: {
type: 'array',
maxItems: 3,
items: { type: 'integer' }
},
nullableKey: { type: ['number', 'null'] }, // or { type: 'number',
multipleTypesKey: { type: ['boolean', 'number'] },
multipleRestrictedTypesKey: {
oneOf: [
{ type: 'string', maxLength: 5 },
{ type: 'number', minimum: 10 }
]
},
enumKey: {
type: 'string',
enum: ['John', 'Foo']
},
notTypeKey: {
not: { type: 'array' }
}
}
}
const queryStringJsonSchema = {
name: { type: 'string' },
excitement: { type: 'integer' }
}
const paramsJsonSchema = {
type: 'object',
properties: {
par1: { type: 'string' },
par2: { type: 'number' }
}
}
const headersJsonSchema = {
type: 'object',
properties: {
'x-foo': { type: 'string' }
},
required: ['x-foo']
}
const schema = {
body: bodyJsonSchema,
querystring: queryStringJsonSchema,
params: paramsJsonSchema,
headers: headersJsonSchema
}
Note that Ajv will try to coerce the values to the types specified in your schema type
keywords, both to pass the validation and to use the correctly typed data afterwards.
Thanks to the addSchema API, you can add multiple schemas to the Fastify
instance and then reuse them in multiple parts of your application. As usual, this
API is encapsulated.
There are two ways to reuse your shared schemas:
replace-way
myField: 'foobar#' will search for a shared schema added with $id:
'foobar'
$ref-way
myField: { $ref: '#foo'} will search for field with $id: '#foo' inside
the current schema
myField: { $ref: '#/definitions/foo'} will search for field
definitions.foo inside the current schema
More examples:
fastify.addSchema({
$id: 'http://example.com/common.json',
type: 'object',
properties: {
hello: { type: 'string' }
}
})
fastify.route({
method: 'POST',
url: '/',
schema: {
body: {
type: 'array',
items: { $ref: 'http://example.com/common.json#/properties/hello'
}
},
handler: () => {}
})
fastify.addSchema({
$id: 'greetings',
type: 'object',
properties: {
hello: { type: 'string' }
}
})
fastify.route({
method: 'POST',
url: '/',
schema: {
body: 'greetings#'
},
handler: () => {}
})
/**
* In children's scope can use schemas defined in upper scope like 'g
* Parent scope can't use the children schemas.
*/
instance.addSchema({
$id: 'framework',
type: 'object',
properties: {
fastest: { type: 'string' },
hi: 'greetings#'
}
})
instance.route({
method: 'POST',
url: '/sub',
schema: {
body: 'framework#'
},
handler: () => {}
})
done()
})
You can use the shared schema everywhere, as top level schema or nested inside
other schemas:
fastify.addSchema({
$id: 'greetings',
type: 'object',
properties: {
hello: { type: 'string' }
}
})
fastify.route({
method: 'POST',
url: '/',
schema: {
body: {
type: 'object',
properties: {
greeting: 'greetings#',
timestamp: { type: 'number' }
}
}
},
handler: () => {}
})
The function getSchemas returns the shared schemas available in the selected
scope:
URL Schemas
/ one
Ajv Plugins
You can provide a list of plugins you want to use with Ajv:
fastify.route({
method: 'POST',
url: '/',
schema: {
body: {
$patch: {
source: {
type: 'object',
properties: {
q: {
type: 'string'
}
}
},
with: [
{
op: 'add',
path: '/properties/q',
value: { type: 'number' }
}
]
}
}
},
handler (req, reply) {
reply.send({ ok: 1 })
}
})
fastify.route({
method: 'POST',
url: '/',
schema: {
body: {
$merge: {
source: {
type: 'object',
properties: {
q: {
type: 'string'
}
}
},
with: {
required: ['q']
}
}
}
},
handler (req, reply) {
reply.send({ ok: 1 })
}
})
Schema Compiler
The schemaCompiler is a function that returns a function that validates the body,
url parameters, headers, and query string. The default schemaCompiler returns a
function that implements the ajv validation interface. Fastify uses it internally to
speed the validation up.
If you want to change or set additional config options, you will need to create your
own instance and override the existing one like:
// -------
// Alternatively, you can set the schema compiler using the setter prop
fastify.schemaCompiler = function (schema) { return ajv.compile(schema)
Note: If you use a custom instance of any validator (even Ajv), you have to add
schemas to the validator instead of fastify, since fastify's default validator is no longer
used, and fastify's addSchema method has no idea what validator you are using.
But maybe you want to change the validation library. Perhaps you like Joi . In this
case, you can use it to validate the url parameters, body, and query string!
fastify.post('/the/url', {
schema: {
body: Joi.object().keys({
hello: Joi.string().required()
}).required()
},
schemaCompiler: schema => data => Joi.validate(data, schema)
}, handler)
Schema Resolver
This is needed because all the schemas you add to your custom compiler are
unknown to Fastify but it need to resolve the $ref paths.
ajv.addSchema({
$id: 'urn:schema:foo',
definitions: {
foo: { type: 'string' }
},
type: 'object',
properties: {
foo: { $ref: '#/definitions/foo' }
}
})
ajv.addSchema({
$id: 'urn:schema:response',
type: 'object',
required: ['foo'],
properties: {
foo: { $ref: 'urn:schema:foo#/definitions/foo' }
}
})
ajv.addSchema({
$id: 'urn:schema:request',
type: 'object',
required: ['foo'],
properties: {
foo: { $ref: 'urn:schema:foo#/definitions/foo' }
}
})
fastify.route({
method: 'POST',
url: '/',
schema: {
body: ajv.getSchema('urn:schema:request').schema,
response: {
'2xx': ajv.getSchema('urn:schema:response').schema
}
},
handler (req, reply) {
reply.send({ foo: 'bar' })
}
})
Serialization
Usually you will send your data to the clients via JSON, and Fastify has a powerful
tool to help you, fast-json-stringify, which is used if you have provided an output
schema in the route options. We encourage you to use an output schema, as it will
increase your throughput by 100-400% depending on your payload and will prevent
accidental disclosure of sensitive information.
Example:
const schema = {
response: {
200: {
type: 'object',
properties: {
value: { type: 'string' },
otherValue: { type: 'boolean' }
}
}
}
}
const schema = {
response: {
'2xx': {
type: 'object',
properties: {
value: { type: 'string' },
otherValue: { type: 'boolean' }
}
},
201: {
type: 'object',
properties: {
value: { type: 'string' }
}
}
}
}
If you need a custom serializer in a very specific part of your code, you can set one
with reply.serializer(...) .
Error Handling
When schema validation fails for a request, Fastify will automtically return a status
400 response including the result from the validator in the payload. As an example,
if you have the following schema for your route
const schema = {
body: {
type: 'object',
properties: {
name: { type: 'string' }
},
required: ['name']
}
}
and fail to satisfy it, the route will immediately return a response with the following
payload
{
"statusCode": 400,
"error": "Bad Request",
"message": "body should have required property 'name'"
}
If you want to handle errors inside the route, you can specify the
attachValidation option for your route. If there is a validation error, the
validationError property of the request will contain the Error object with the
raw validation result as shown below
You can also use setErrorHandler to define a custom response for validation errors
such as
If you want custom error response in schema without headaches and quickly, you
can take a look at here
shared schema
$ref to $id
Use Case Validator Serializer
$ref to /definitions
Examples
const sharedSchema = {
type: 'object',
properties: {
home: 'sharedAddress#',
work: 'sharedAddress#'
}
}
const refToSharedSchemaId = {
type: 'object',
properties: {
home: { $ref: 'http://foo/common.json#address' },
work: { $ref: 'http://foo/common.json#address' }
}
}
const refToSharedSchemaDefinitions = {
type: 'object',
properties: {
home: { $ref: 'http://foo/common.json#/definitions/foo' },
work: { $ref: 'http://foo/common.json#/definitions/foo' }
}
}
Resources
JSON Schema
Understanding JSON schema
fast-json-stringify documentation
Ajv documentation
Ajv i18n
Ajv custom errors
Custom error handling with core methods with error file dumping example