-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for fastify 5 #296
Comments
Thanks for the heads up! Should be able to start on this soon. |
Any news about this ? |
I'm joining the crowd wishing for a swift resolution to this. Considering there's two open pr's trying to solve the same thing I hope the maintainers push for one of them soon. |
I see, should we fork the repo, merge the PR and publish it under another org? It's been a while since I opened the issue |
@olyop @trevor-scheer Could you please take a gander at the two prs? |
Any update on this? I'm stuck on my Fastify/Nest server updates as well due to this. |
Hello! Any update on support for Fastify version 5? |
any news on this? |
Workaround. Use
"@as-integrations/fastify": "patch:@as-integrations/fastify@npm%3A2.1.1#~/.yarn/patches/@as-integrations-fastify-npm-2.1.1-6c130ea02e.patch",
|
This integration seems unmaintained and dead. Forking it is likely the solution, but for me this means I'll stay with the official express integration instead. |
Until an update is released, here's something I cooked up that might be of use; import { Readable } from 'node:stream'
import {
type ApolloServer,
HeaderMap,
type HTTPGraphQLRequest,
type HTTPGraphQLResponse,
} from '@apollo/server'
import { type FastifyReply, type FastifyRequest } from 'fastify'
import plugin from 'fastify-plugin'
import { type Context, createContext } from './server/context'
export function fastifyApollo(apollo: ApolloServer<Context>) {
return plugin(
(fastify) => {
fastify.route({
async handler(request, reply) {
const response = await apollo.executeHTTPGraphQLRequest({
context: () => createContext(request, reply),
httpGraphQLRequest: createRequest(request),
})
return handleResponse(reply, response)
},
method: ['get', 'post', 'options'],
url: '/graphql',
})
},
{
fastify: '5.x',
name: 'apollo',
},
)
}
function createRequest(request: FastifyRequest): HTTPGraphQLRequest {
const url = new URL(request.url, `${request.protocol}://${request.hostname}`)
const headers = new HeaderMap()
for (const [key, value] of Object.entries(request.headers)) {
if (value) {
headers.set(key, Array.isArray(value) ? value.join(', ') : value)
}
}
return {
body: request.body,
headers,
method: request.method.toUpperCase(),
search: url.search,
}
}
function handleResponse(
reply: FastifyReply,
{ body, headers, status }: HTTPGraphQLResponse,
) {
for (const [key, value] of headers) {
void reply.header(key, value)
}
void reply.code(status ?? 200)
if (body.kind === 'complete') {
return body.string
}
const readable = Readable.from(body.asyncIterator)
return reply.send(readable)
} Usage; await fastify.register(fastifyApollo(apollo)) Most of the code is copied from this package and refactored a bit. Does anybody know if |
Hey y'all. Sorry for the silence here, unfortunately priorities have taken my attention elsewhere.
I can't commit to helping with this work but I would like to enable you folks to do it. |
Hey @trevor-scheer, sorry to prod, but just wanted to check in. Is there anything we can do to help here? |
It looks like @olyop is no longer active: https://github.com/olyop?tab=overview&from=2024-12-01&to=2024-12-31. Is anyone available to at least review and accept pull requests? That would be great. Alternatively, bringing in new contributors could help keep this official plugin—mentioned on https://www.apollographql.com/docs/apollo-server—alive. Thanks for taking action! |
Here is the updated version of the plugin (including fastifyApolloDrainPlugin), which is based on the original one, but less overloaded with generic parameters. P.S. Just as the original repo it requires fastify-plugin to be installed. // --- Types
interface FastifyApolloPluginContext<Context extends BaseContext> {
context?: ApolloFastifyContextFunction<Context>;
}
type ApolloFastifyContextFunctionArgument = [request: FastifyRequest, reply: FastifyReply];
type ApolloFastifyContextFunction<Context extends BaseContext> = ContextFunction<
ApolloFastifyContextFunctionArgument,
Context
>;
type FastifyApolloPluginOptions<Context extends BaseContext> = FastifyRegisterOptions<
FastifyApolloPluginContext<Context>
>;
// --- Plugins
// Inspired by outdated fastify apollo plugin:
// https://github.com/apollo-server-integrations/apollo-server-integration-fastify/blob/main/src/plugin.ts
const fastifyApollo = <Context extends BaseContext = BaseContext>(
apollo: ApolloServer<Context>,
): FastifyPluginAsync => {
const apolloServerProvided = (value: unknown): boolean => value instanceof ApolloServer;
if (!apolloServerProvided(apollo)) throw new Error('Apollo server instance is not provided');
apollo.assertStarted('fastifyApollo()');
// See: https://github.com/fastify/fastify-plugin?tab=readme-ov-file#metadata
const pluginMetadata: PluginMetadata = {
fastify: '^5.2', // This may be different for you based on your installed version of fastify
name: 'fastifyApollo',
};
const fastifyRequestToGraphQLRequest = (request: FastifyRequest): HTTPGraphQLRequest => {
const httpHeadersToMap = (headers: IncomingHttpHeaders): HeaderMap => {
const map = new HeaderMap();
for (const [key, value] of Object.entries(headers)) {
if (value) {
map.set(key, Array.isArray(value) ? value.join(', ') : value);
}
}
return map;
};
return {
body: request.body,
method: request.method.toUpperCase(),
headers: httpHeadersToMap(request.headers),
search: new URL(request.url, `${request.protocol}://${request.hostname}/`).search,
};
};
const fastifyApolloHandler = <Context extends BaseContext>(
apollo: ApolloServer<Context>,
options: FastifyApolloPluginContext<Context>,
): RouteHandlerMethod => {
const defaultContext: ApolloFastifyContextFunction<Context> = () => Promise.resolve({} as Context);
const contextFunction = options?.context ?? defaultContext;
return async (request: FastifyRequest, reply: FastifyReply): Promise<string> => {
const httpGraphQLResponse = await apollo.executeHTTPGraphQLRequest({
httpGraphQLRequest: fastifyRequestToGraphQLRequest(request),
context: () => contextFunction(request, reply),
});
const {headers, body, status} = httpGraphQLResponse;
for (const [headerKey, headerValue] of headers) {
void reply.header(headerKey, headerValue);
}
void reply.code(status === undefined ? 200 : status);
if (body.kind === 'complete') {
return body.string;
}
const readable = Readable.from(body.asyncIterator);
return reply.send(readable);
};
};
return fastifyPlugin(async (fastify: FastifyInstance, options: FastifyApolloPluginContext<Context>): Promise<void> => {
const path = '/graphql';
const method = ['GET', 'POST', 'OPTIONS'];
fastify.route({
method,
url: path,
handler: fastifyApolloHandler<Context>(apollo, options),
});
}, pluginMetadata);
};
// Inspired by outdated fastify apollo drain plugin:
// https://github.com/apollo-server-integrations/apollo-server-integration-fastify/blob/main/src/drain-plugin.ts
const fastifyApolloDrainPlugin = (fastify: FastifyInstance): ApolloServerPlugin => {
return {
async serverWillStart(): Promise<GraphQLServerListener> {
return {
async drainServer(): Promise<void> {
// `closeAllConnections` was added in v18.2 - @types/node are v16.
if ('closeAllConnections' in fastify.server) {
// If fastify.close() takes longer than 10 seconds - run the logic to force close all connections
const timeout = setTimeout(() => {
fastify.server.closeAllConnections();
}, 10_000);
await fastify.close();
clearTimeout(timeout);
}
},
};
},
};
};
// --- Usage
interface MyContext {
// Here I use an auth token as a part of the context, you may have a different context
authToken: string;
}
const extractAuthToken: ApolloFastifyContextFunction<MyContext> = async (request: FastifyRequest) => {
// ... Your logic goes here
};
const app = fastify();
// Apollo server initialization logic, you may have it different
const server = new ApolloServer<MyContext>({
schema,
plugins: [fastifyApolloDrainPlugin(app)],
});
// Spin up the Apollo server
await server.start();
// Register the plugin
await app.register<FastifyApolloPluginOptions<MyContext>>(fastifyApollo(server), {
context: extractAuthToken
});
// Spin up the fastify server
await app.listen({
port: 4000 // ... or whatever your port number is
}); |
fastify@5
is released 😃.@as-integrations/fastify
peerDependencies includefastify@^4.4.0
. Please consider releasing a new version supportingfastify@5
.The text was updated successfully, but these errors were encountered: