Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,20 @@ the `content-length` header.
}
```

`onResponse` may also be async when you need to read the upstream response
before sending a replacement body:

```js
{
async onResponse (request, reply, res) {
const data = await new Response(res.stream).json()
reply.send({ ...data, proxied: true })
}
}
```

Handle errors inside async `onResponse` callbacks before replying.

**Note**: `onResponse` is called after headers have already been sent. If you want to modify response headers, use the `rewriteHeaders` hook.

#### `onError(reply, error)`
Expand Down
35 changes: 35 additions & 0 deletions test/onResponse.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,38 @@ t.test('onResponse', async (t) => {
t.assert.strictEqual(result.statusCode, 200)
t.assert.strictEqual(await result.body.text(), 'hello world')
})

t.test('async onResponse', async (t) => {
t.plan(6)

const instance = Fastify()
instance.register(From)
t.after(() => instance.close())

const target = http.createServer((req, res) => {
t.assert.ok('request proxied')
t.assert.strictEqual(req.method, 'GET')
res.statusCode = 200
res.end('hello world')
})

instance.get('/async', (request1, reply) => {
reply.from(`http://localhost:${target.address().port}`, {
async onResponse (request2, reply, res) {
await Promise.resolve()
t.assert.strictEqual(res.statusCode, 200)
t.assert.strictEqual(request1.raw, request2.raw)
reply.send(res.stream)
}
})
})

t.after(() => target.close())

await instance.listen({ port: 0 })
await new Promise(resolve => target.listen({ port: 0 }, resolve))

const result = await request(`http://localhost:${instance.server.address().port}/async`)
t.assert.strictEqual(result.statusCode, 200)
t.assert.strictEqual(await result.body.text(), 'hello world')
})
2 changes: 1 addition & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ declare namespace fastifyReplyFrom {
request: FastifyRequest<RequestGenericInterface, RawServerBase>,
reply: FastifyReply<RouteGenericInterface, RawServerBase>,
res: RawServerResponse<RawServerBase>
) => void;
) => void | Promise<void>;
onError?: (
reply: FastifyReply<RouteGenericInterface, RawServerBase>,
error: { error: Error }
Expand Down
10 changes: 10 additions & 0 deletions types/index.tst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,16 @@ app.get('/v3', (_request, reply) => {
})
})

app.get('/async-on-response', (_request, reply) => {
reply.from('/async-on-response', {
async onResponse (request, reply, res) {
expect(request).type.toBe<FastifyRequest<RequestGenericInterface, RawServerBase>>()
expect(reply).type.toBe<FastifyReply<RouteGenericInterface, RawServerBase>>()
expect(res).type.toBe<RawServerResponse<RawServerBase>>()
}
})
})

app.get('/http2', (_request, reply) => {
reply.from('/', {
method: 'POST',
Expand Down
Loading