My Fastify server needs to proxy a request to another service, and when I get the response I am trying to just pass the stream back down to the client, but the response is empty. Here's an example I created using a popular open API; Star Wars API.
const fastify = require("fastify")({ logger: true });
// return JSON from SWAPI - works!
fastify.get("/api/json", async (request, reply) => {
const response = await fetch("https://swapi.dev/api/people/1/");
const json = await response.json();
return reply.send(json);
});
// return stream from SWAPI - doesn't work
// response is an empty object: {}
fastify.get("/api/stream", async (request, reply) => {
const response = await fetch("https://swapi.dev/api/people/1/");
return reply.send(response.body);
});
fastify.listen({ port: 3000 }, (err) => {
if (err) {
fastify.log.error(err);
process.exit(1);
}
});
Above is the entire server file, but you can also clone my GitHub repo if you want to: https://github.com/TJBlackman/fastify-stream-test
A Fastify contributor actually answered this question on Github:
'use strict' import { Readable } from "node:stream"; const fastify = require(".")({ logger: true }); fastify.get("/api/stream", async (request, reply) => { const response = await fetch("https://swapi.dev/api/people/1/"); const stream = Readable.fromWeb(response.body); return reply.send(stream); }); fastify.listen({ port: 3000 }, (err) => { if (err) { fastify.log.error(err); process.exit(1); } });
I guess, fetch returns a WHATWG Stream, which is not providing a pipe method, thus not being streamed when using reply.send.
The Fastify team merged a PR to fix this, and now it just works, as long as you're on Fastify v4.26.0 or higher!
fastify.get("/api/stream", async (request, reply) => {
const response = await fetch("https://swapi.dev/api/people/1/");
return reply.send(response.body);
});