|
| 1 | +# Fastify Adapter |
| 2 | + |
| 3 | +oRPC supports [Fastify](https://fastify.dev/) servers out of the box. |
| 4 | + |
| 5 | +## Server Usage |
| 6 | + |
| 7 | +::: code-group |
| 8 | + |
| 9 | +```ts [RPC] |
| 10 | +import { onError } from '@orpc/server' |
| 11 | +import { RPCHandler } from '@orpc/server/fastify' |
| 12 | +import { CORSHandlerPlugin } from '@orpc/server/plugins' |
| 13 | +import Fastify from 'fastify' |
| 14 | + |
| 15 | +const handler = new RPCHandler(router, { |
| 16 | + plugins: [ |
| 17 | + new CORSHandlerPlugin() |
| 18 | + ], |
| 19 | + interceptors: [ |
| 20 | + onError((error) => { |
| 21 | + console.error(error) |
| 22 | + }), |
| 23 | + ], |
| 24 | +}) |
| 25 | + |
| 26 | +const app = Fastify() |
| 27 | + |
| 28 | +app.all('/rpc/*', async (req, reply) => { |
| 29 | + const { matched } = await handler.handle(req, reply, { |
| 30 | + prefix: '/rpc', |
| 31 | + context: {} // Provide initial context if needed |
| 32 | + }) |
| 33 | + |
| 34 | + if (matched) { |
| 35 | + return reply |
| 36 | + } |
| 37 | + |
| 38 | + return reply.status(404).send('Not found') |
| 39 | +}) |
| 40 | + |
| 41 | +app.listen({ port: 3000 }).then(() => console.log('Listening on port 3000')) |
| 42 | +``` |
| 43 | + |
| 44 | +```ts [OpenAPI] |
| 45 | +import { OpenAPIHandler } from '@orpc/openapi/fastify' |
| 46 | +import { onError } from '@orpc/server' |
| 47 | +import { CORSHandlerPlugin } from '@orpc/server/plugins' |
| 48 | +import Fastify from 'fastify' |
| 49 | + |
| 50 | +const handler = new OpenAPIHandler(router, { |
| 51 | + plugins: [ |
| 52 | + new CORSHandlerPlugin() |
| 53 | + ], |
| 54 | + interceptors: [ |
| 55 | + onError((error) => { |
| 56 | + console.error(error) |
| 57 | + }), |
| 58 | + ], |
| 59 | +}) |
| 60 | + |
| 61 | +const app = Fastify() |
| 62 | + |
| 63 | +app.all('/api/*', async (req, reply) => { |
| 64 | + const { matched } = await handler.handle(req, reply, { |
| 65 | + prefix: '/api', |
| 66 | + context: {} // Provide initial context if needed |
| 67 | + }) |
| 68 | + |
| 69 | + if (matched) { |
| 70 | + return reply |
| 71 | + } |
| 72 | + |
| 73 | + return reply.status(404).send('Not found') |
| 74 | +}) |
| 75 | + |
| 76 | +app.listen({ port: 3000 }).then(() => console.log('Listening on port 3000')) |
| 77 | +``` |
| 78 | + |
| 79 | +::: |
| 80 | + |
| 81 | +::: tip |
| 82 | +Fastify only accepts content types it has a registered parser for, and parses request bodies itself. For the best oRPC experience, register a catch-all parser with `app.addContentTypeParser('*', ...)` so every content type is supported, and call `app.removeAllContentTypeParsers()` so every body is parsed by oRPC instead of Fastify: |
| 83 | + |
| 84 | +```ts |
| 85 | +// Optional, let oRPC parse all content types |
| 86 | +app.removeAllContentTypeParsers() |
| 87 | + |
| 88 | +// Optional, support all content types |
| 89 | +app.addContentTypeParser('*', (request, payload, done) => { |
| 90 | + done(null, undefined) |
| 91 | +}) |
| 92 | +``` |
| 93 | + |
| 94 | +::: |
| 95 | + |
| 96 | +<!--@include: @/shared/standard-server-cors-warning.md --> |
| 97 | + |
| 98 | +## Event Stream Options |
| 99 | + |
| 100 | +You can configure how an [AsyncIteratorObject](/docs/async-iterator-object) is streamed to the client using the `sendStandardResponse.eventStream` options when creating the handler. |
| 101 | + |
| 102 | +```ts |
| 103 | +const handler = new OpenAPIHandler(router, { |
| 104 | + sendStandardResponse: { |
| 105 | + eventStream: { |
| 106 | + initialComment: { |
| 107 | + /** |
| 108 | + * If true, an initial comment is sent immediately upon stream start to flush headers. |
| 109 | + * This allows the receiving side to establish the connection without waiting for the first event. |
| 110 | + * |
| 111 | + * @default true |
| 112 | + */ |
| 113 | + enabled: true, |
| 114 | + /** |
| 115 | + * The content of the initial comment sent upon stream start. Must not include newline characters. |
| 116 | + * |
| 117 | + * @default '' |
| 118 | + */ |
| 119 | + comment: '', |
| 120 | + }, |
| 121 | + keepAlive: { |
| 122 | + /** |
| 123 | + * If true, a ping comment is sent periodically to keep the connection alive. |
| 124 | + * |
| 125 | + * @default true |
| 126 | + */ |
| 127 | + enabled: true, |
| 128 | + /** |
| 129 | + * Interval (in milliseconds) between ping comments sent after the last event. |
| 130 | + * |
| 131 | + * @default 15000 |
| 132 | + */ |
| 133 | + interval: 15000, |
| 134 | + /** |
| 135 | + * The content of the ping comment. Must not include newline characters. |
| 136 | + * |
| 137 | + * @default '' |
| 138 | + */ |
| 139 | + comment: '', |
| 140 | + }, |
| 141 | + /** |
| 142 | + * If true, a `close` event is sent even when the iterator completes with `undefined`. |
| 143 | + * When the iterator returns a value, a `close` event is always emitted regardless of this setting. |
| 144 | + * |
| 145 | + * @default true |
| 146 | + */ |
| 147 | + emptyCloseEventEnabled: true, |
| 148 | + }, |
| 149 | + }, |
| 150 | +}) |
| 151 | +``` |
0 commit comments