A radically simple API routing and method injection plugin for Fastify.
Uses fastify.inject
under the hood, with developer ergonomics in mind.
Injects fastify.api.client
with automatically mapped methods from route definitions. Also injects fastify.api.meta
, which you can serve and use manifetch
to automatically build an API client for the browser.
- Original fastify.{method}() with
exposeAs
option, without params:
fastify.get('/1/method', { exposeAs: 'method' }, (_, reply) => {
reply.send('Hello from /1/method')
})
fastify.get('/invoke/1/method', async (_, reply) => {
const result = await fastify.api.client.method()
reply.send(result)
})
- Original fastify.{method}() with
exposeAs
option, with params:
fastify.get('/2/method/:id', { exposeAs: 'methodWithParams' }, ({ id }, _, reply) => {
reply.send(`Hello from /2/method/ with id ${id}`)
})
fastify.get('/invoke/2/method', async (req, reply) => {
const result = await fastify.api.client.methodWithParams({ id: 123 })
reply.send(result)
})
- Will automatically create a nested structure too, if needed:
fastify.get('/3/nested/method/:id', { exposeAs: 'nested.method' }, ({ id }, _, reply) => {
reply.send(`Hello from /3/nested/method/ with id ${id}`)
})
fastify.get('/invoke/3/nested/method', async (req, reply) => {
const result = await fastify.api.client.nested.method({ id: 123 })
reply.send(result)
})
- Modified fastify.api.{method}() setter if the handler is a named function:
fastify.api.get('/4/method', function methodFromNamedFunction ({ id }, _, reply) {
reply.send(`Hello from /4/method with id ${id}`)
})
fastify.get('/invoke/4/method', async (req, reply) => {
const result = await fastify.api.client.methodFromNamedFunction({ id: 123 })
reply.send(result)
})
- Modified fastify.api(setter) helper to quickly define multiple methods:
Makes more sense if the setter function is coming from another file.
fastify.api(({ get }) => ({
topLevelMethod: get('/5/top-level-method/:id', function ({ id }, _, reply) {
reply.send({ id })
}),
nestedMethods: {
method: get('/5/nested-methods/method/:id', ({ id }, _, reply) => {
reply.send({ id })
}),
otherMethod: get('/5/nested-methods/other-method/:id', ({ id }, _, reply) => {
reply.send({ id })
}),
deeplyNestedMethods: {
method: get('/5/nested-methods/deeply-nested-methods/method/:id', ({ id }, _, reply) => {
reply.send({ id })
}),
otherMethod: get('/5/nested-methods/deeply-nested-methods/other-method/:id', ({ id }, _, reply) => {
reply.send({ id })
})
}
}
}))
fastify.get('/invoke/5/top-level-method', async (req, reply) => {
const result = await fastify.api.client.topLevelMethod({ id: 123 })
reply.send(result)
})
fastify.get('/invoke/5/nested-methods/method', async (_, reply) => {
const result = await fastify.api.client.nestedMethods.method({ id: 123 })
reply.send(result)
})
fastify.get('/invoke/5/nested-methods/other-method', async (_, reply) => {
const result = await fastify.api.client.nestedMethods.otherMethod({ id: 123 })
reply.send(result)
})
fastify.get('/invoke/5/nested-methods/deeply-nested-methods/method', async (_, reply) => {
const result = await fastify.api.client.nestedMethods.deeplyNestedMethods.method({ id: 123 })
reply.send(result)
})
fastify.get('/invoke/5/nested-methods/deeply-nested-methods/other-method', async (_, reply) => {
const result = await fastify.api.client.nestedMethods.deeplyNestedMethods.otherMethod({ id: 123 })
reply.send(result)
})
- Any API method exposed in fastify.api.client can take options:
fastify.get('/6/method', { exposeAs: 'methodWithOptions' }, (req, reply) => {
reply.send(`Hello from /6/method/ with query.arg ${
req.query.arg
} and the x-foobar header ${
req.headers['x-foobar']
}`)
})
fastify.get('/invoke/6/method', async (_, reply) => {
const result = await fastify.api.client.methodWithOptions({
query: {
arg: 1
},
headers: {
'x-foobar': 1
}
})
reply.send(result)
})
If you call a route via HTTP, it'll operate normally as if weren't using the plugin. If you use fastify.api.client.xyz()
to invoke it from another handler, you'll get an object containing { json, body, status, headers }
as response. If it's unable to parse a JSON document out of body
, json
is undefined.