Fastify
One plugin, hooked onRequest for verification and preHandler for idempotency.
The block below is executed against the real @keyring/fastify by the docs' test suite.
import Fastify from 'fastify';
import { keyringPlugin } from '@keyring/fastify';
const liveOrders = [{ id: 'ord_live_1', total: 4200 }];
const testOrders = [{ id: 'ord_test_1', total: 100 }];
const app = Fastify();
await app.register(keyringPlugin, {
resources: { orders: { live: liveOrders, test: testOrders } },
});
app.get('/v1/orders', async (request) => ({
tenant: request.keyring?.tenantId,
env: request.keyring?.env,
degraded: request.keyring?.degraded,
orders: request.keyring?.orders,
}));
await app.listen({ port: Number(process.env.PORT ?? 3000), host: '127.0.0.1' });
process.stdout.write('listening\n');request.keyring is decorated on every request at creation, so unlike Express its KeyringContext | null guarantee holds unconditionally, including in hooks registered before the plugin. It is null on a route configured skip: true.
Hooks, and why these ones
- Verification hooks
onRequest, deliberately before body parsing, so a denied request never reaches the JSON parser. - Idempotency hooks
preHandler, the opposite case, because it has to hash a body it therefore has to wait for. No second registration is needed. onResponseandonRequestAbortemit the usage event, so a caller that hangs up mid-request still appears in your usage.
The plugin is wrapped in fastify-plugin, so request.keyring is visible to the routes you register rather than to an encapsulated child context. Register it before your own onRequest authentication if Keyring owns the route, after it if your session does.
Options
keyringPlugin takes every KeyringOptions field, or an already-constructed instance when one process serves several projects. Per-route rules go in routes, keyed the same way as on Express.