fastify/session

Fastify Session - Does not set cookies when using `res.raw`

gino opened this issue · 4 comments

gino commented

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the issue has not already been raised

Issue

Hi there,

I am using Fastify in combination with @fastify/session (with the required cookie plugin aswell) and graphql-helix with this fastify example. In this example, you can see that on line 37 res.raw is being used. However, whenever I use this in combination with req.session, the cookie does not get set whenever I am in the /graphql endpoint.

But whenever I use req.session in a regular endpoint, it does work. For example:

// The cookie does get set
app.get("/", (req, res) => {
  if (!req.session.test) {
    req.session.test = "some testing value";
  }

  res.send({ session: req.session.test });
});

So I think this has something to do with the res.raw or something similar to graphql-helix. I am not quite sure if this is a bug or if this has something to do with graphql-helix.

I hope someone is being able to help me out here. Thanks!

Edit: I assume that this could be expected behaviour since I am using res.raw. However, passing res instead of res.raw results in a few errors which makes sense and explains why res.raw is being used instead.

This module is not compatible with using something like graphql-helix as it bypass fastify by using res.raw. I would recommend you to use https://mercurius.dev/#/ instead

graphql-helix does not necessarily require using res.raw. As fastify is able to accept a Readable stream for reply.send, you can cast the helix execution result from an async iterable to a Readable stream.

We are currently adding these helpers over here: contra/graphql-helix#228

The full setup look like this:

import fastify from "fastify";
import { getGraphQLParameters, processRequest, renderGraphiQL, shouldRenderGraphiQL } from "graphql-helix";
import { toResponsePayload } from "graphql-helix/to-response-payload";
import { toReadable } from "graphql-helix/node/to-readable";
import { schema } from "./schema";
const app = fastify();
app.route({
  method: ["GET", "POST"],
  url: "/graphql",
  async handler(req, reply) {
    const request = {
      body: req.body,
      headers: req.headers,
      method: req.method,
      query: req.query,
    };
    if (shouldRenderGraphiQL(request)) {
      reply.type("text/html");
      reply.send(renderGraphiQL({}));
    } else {
      const request = {
        body: req.body,
        headers: req.headers,
        method: req.method,
        query: req.query,
      };
      const { operationName, query, variables } = getGraphQLParameters(request);
      const result = await processRequest({
        operationName,
        query,
        variables,
        request,
        schema,
      });
      const responsePayload = toResponsePayload(result);
      reply.status(responsePayload.status);
      reply.headers(responsePayload.headers);
      reply.send(toReadable(responsePayload.source));
    }
  },
});
const port = process.env.PORT || 4000;
app.listen(port, () => {
  console.log(`GraphQL server is running on port ${port}.`);
});

You can use any fastify plugin with it 9https://github.com/contrawork/graphql-helix/blob/657488c43dda17eddb6713a9acb1a168b4265330/packages/core/test/integration.test.ts#L667-L704)

In the future it would definitely be great if reply.send would also accept an async iterable in addition to streams.

I don't think you need special wrappers to move from an async iterator to a stream, you can just do Readable.from() and it will do the trick.

@mcollina Thank you for the tip, I will test it!