Guides
Defining Routes
How to define routes, groups, and attach metadata
Route basics
Every HTTP method returns a builder that you configure entirely through chaining:
api.get('/users/:id')
.params(Type.Object({ id: Type.String() }))
.query(Type.Object({ fields: Type.Optional(Type.String()) }))
.response(User)
.error(404, ErrorSchema)
.summary('Get a user by ID')
.operationId('getUser')
.tag('users')Request inputs (params, query, headers, cookies, body) and responses are all set via chained methods.
Response methods
| Method | Usage |
|---|---|
.response(schema) | Shorthand for a 200 response |
.respond(status, schema) | Response for any status code |
.error(status, schema) | Error response |
Status codes accept numbers or OpenAPI wildcards: '1XX', '2XX', '3XX', '4XX', '5XX', 'default'.
api.post('/users')
.body(CreateUser)
.respond(201, User)
.error(422, ValidationError)
.error('4XX', GenericError)
.summary('Create a user')Groups
Groups collect routes under a shared path prefix with inherited metadata:
import { Api, named } from '@spec-spac/spac'
import { Type } from '@sinclair/typebox'
const User = named('User', Type.Object({ id: Type.String(), name: Type.String() }))
const CreateUser = named('CreateUser', Type.Object({ name: Type.String() }))
const Post = named('Post', Type.Object({ id: Type.String(), title: Type.String() }))
const api = new Api('3.1', 'Groups Example')
api.group('/users', g => {
g.get('/').response(Type.Array(User))
g.post('/').body(CreateUser).response(User)
g.group('/:userId/posts', posts => {
posts.get('/').response(Type.Array(Post))
})
}).tag('users').security({ bearer: [] })
export default apiopenapi: 3.1.2
info:
title: Groups Example
version: 1.0.0
jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
paths:
/users:
get:
responses:
"200":
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/User"
post:
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/CreateUser"
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/User"
/users/:userId/posts:
get:
responses:
"200":
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Post"
components:
schemas:
User:
type: object
required:
- id
- name
properties:
id:
type: string
name:
type: string
CreateUser:
type: object
required:
- name
properties:
name:
type: string
Post:
type: object
required:
- id
- title
properties:
id:
type: string
title:
type: string
security:
- bearer: []
tags:
- name: usersTags and security set on a group cascade to all child routes.
Links
Links describe follow-up operations using values from the response (OpenAPI Link Object):
api.post('/pets')
.body(CreatePet)
.respond(201, Pet)
.link(201, 'GetPetById', {
operationId: 'getPet',
parameters: { petId: '$response.body#/id' },
})Without a status code, links attach to the 200 response:
api.get('/pets/:petId')
.params(Type.Object({ petId: Type.String() }))
.response(Pet)
.link('GetOwner', {
operationId: 'getOwner',
parameters: { ownerId: '$response.body#/ownerId' },
})Macros
Macros are reusable transforms applied via .use():
import { Api, named, macro } from '@spec-spac/spac'
import { Type } from '@sinclair/typebox'
const ErrorSchema = named('Error', Type.Object({ message: Type.String() }))
const Pet = named('Pet', Type.Object({ id: Type.String(), name: Type.String() }))
const authenticated = macro.route(r =>
r.security({ bearer: [] }).error(401, ErrorSchema).error(403, ErrorSchema)
)
const validated = macro.route(r => r.error(422, ErrorSchema))
const api = new Api('3.1', 'Macros Example')
api.securityScheme('bearer', { type: 'http', scheme: 'bearer' })
api.post('/pets')
.body(Pet).response(Pet)
.use(authenticated).use(validated)
export default apiopenapi: 3.1.2
info:
title: Macros Example
version: 1.0.0
jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
paths:
/pets:
post:
security:
- bearer: []
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
"401":
description: ""
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"403":
description: ""
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"422":
description: ""
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
securitySchemes:
bearer:
type: http
scheme: bearer
schemas:
Pet:
type: object
required:
- id
- name
properties:
id:
type: string
name:
type: string
Error:
type: object
required:
- message
properties:
message:
type: stringMacros work at route, group, and api level.