Skip to main content

Validation

info

The examples on this page are written with Fastify, but the same features are valid with Express.

Pull requests to add examples with Express are welcome!


There are two types of validation: automatic validation by Frourio and validation using the class-validator.

Path Parameter

The type can be specified by appending @string or @number to path parameters, and the default in frourio is string.

When the type is specified as number, frourio automatically converts string to number and validates that it is not NaN.

caution

When the type is not specified, there is a difference in the behavior of Frourio and Aspida.

Frourio interprets the type as string as mentioned above, but Aspida interprets it as string | number. This is due to the information loss that occurs as path parameters are passed through an URL.

Unless there are special circumstances, you should specify their types.

Example

API Definition

server/api/tasks/[email protected]/index.ts
import { Task } from '$/types'

export type Methods = {
get: {
resBody: Task
}
}

Controller

server/api/tasks/[email protected]/controller.ts
import { defineController } from './$relay'
import { findTask } from '$/service/tasks'

export default defineController(() => ({
get: async ({ params }) => {
const task = await findTask(params.taskId)

return task ? { status: 200, body: task } : { status: 404 }
},
}))

Results

$ curl http://localhost:8080/api/tasks
[{"id":0,"label":"sample task","done":false}]

$ curl http://localhost:8080/api/tasks/0
{"id":0,"label":"sample task","done":false}

$ curl http://localhost:8080/api/tasks/1 -i
HTTP/1.1 404 Not Found

$ curl http://localhost:8080/api/tasks/abc -i
HTTP/1.1 400 Bad Request

URL Query

When the URL query specified as ...

  • required
    • Frourio automatically validates that it exists.
    • If it isn't and it is specified as array, frourio sets an empty array [].
  • number
    • Frourio automatically converts string to number and validates that it is not NaN.
  • boolean
    • Frourio automatically converts string ('true' or 'false') to boolean.
Depricated

And if its key ends in square brackets (e.g. foo[]), frourio automatically removes the brackets (e.g. foo).

Example

API Definition

server/api/tasks/index.ts
import { Task } from '$/types'

export type Methods = {
get: {
query?: {
limit: number
}
resBody: Task[]
}
}

Controller

server/api/tasks/controller.ts
import { defineController } from './$relay'
import { getTasks } from '$/service/tasks'

export default defineController(() => ({
get: async ({ query }) => ({
status: 200,
body: (await getTasks()).slice(0, query?.limit),
}),
}))

Results

$ curl http://localhost:8080/api/tasks
[{"id":0,"label":"sample task 0","done":false},{"id":1,"label":"sample task 1","done":false},{"id":1,"label":"sample task 2","done":false}]

$ curl http://localhost:8080/api/tasks?limit=1
[{"id":0,"label":"sample task 0","done":false}]

$ curl http://localhost:8080/api/tasks?limit=abc -i
HTTP/1.1 400 Bad Request

Request body

When the reqFormat is specified as FormData, frourio automatically converts and validates it.

  1. If it is array, converts it to array (and if it doesn't exists, set an empty array).
  2. Extracts file or value.
  3. If some values are specified as optional and they are empty, remove them.

class-validator

To validate request body, request headers and URL query, specify a class with class-validator instead of type for reqBody, reqHeaders and query.

Example

Validator

server/validators/index.ts
import { MinLength, IsString } from 'class-validator'

export class LoginBody {
@MinLength(5)
id: string

@MinLength(8)
pass: string
}

export class TokenHeader {
@IsString()
@MinLength(10)
token: string
}

API Definition

server/api/token/index.ts
import { LoginBody, TokenHeader } from '$/validators'

export type Methods = {
post: {
reqBody: LoginBody
resBody: {
token: string
}
}

delete: {
reqHeaders: TokenHeader
}
}

Results

$ curl -X POST -H "Content-Type: application/json" -d '{"id":"correctId","pass":"correctPass"}' http://localhost:8080/api/token
{"token":"XXXXXXXXXX"}

$ curl -X POST -H "Content-Type: application/json" -d '{"id":"abc","pass":"12345"}' http://localhost:8080/api/token -i
HTTP/1.1 400 Bad Request

$ curl -X POST -H "Content-Type: application/json" -d '{"id":"incorrectId","pass":"incorrectPass"}' http://localhost:8080/api/token -i
HTTP/1.1 401 Unauthorized

Passing Validator Options

class-validator options

server/service/app.ts
import Fastify, { FastifyServerFactory } from 'fastify'
import server from '$/$server'

export const init = (serverFactory?: FastifyServerFactory) => {
const app = Fastify({ serverFactory })
server(app, { basePath: '/api', validator: { whitelist: true } })
return app
}