fastify-api
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
with automatically mapped methods from route definitions.
Usage
- 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) => {
try {
const result = await fastify.api.client.method()
reply.send(result)
} catch (err) {
console.error(err)
}
})
- Original fastify.() 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.() 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)
})
API responses
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.