ilijaNL / graphql-ops-proxy

A fast and secure graphql proxy for nodejs, serverless and cf workers
MIT License
4 stars 0 forks source link

Support for using app router latest nextjs version #8

Open nielll opened 1 year ago

nielll commented 1 year ago

Hi,

How to use this graphql proxy with app router and latest Next version?

Is it feasible?

Greetings Niel

ilijaNL commented 1 year ago

What is exactly the use case? Could you provide some code samples

nielll commented 1 year ago

Hi

I found the culprit. There is a bug in the actual version of nextjs. After some logging I discovered that the fetch to the graphql endpoint was failing due to invalid transfer-encoding header.

More details of the bug: https://github.com/vercel/next.js/issues/48214

After removing "transfer-encoding" header the proxy works as expected.

async function _requestRemote(props: RemoteRequestProps): Promise<Response> {
    const requestBody = {
      query: props.query,
      variables: props.variables,
    };

    const bodyPayload = JSON.stringify(requestBody);

    // we since we generating new body ensure this header is not proxied through
    props.headers.delete("content-length");

    props.headers.set("content-type", "application/json");
    props.headers.set("accept", "application/json");

    props.headers.delete("host");
    props.headers.delete("connection");
    props.headers.delete("keep-alive");

    // Fixes error on newer nextjs versions:
    // see: https://github.com/vercel/next.js/issues/48214
    props.headers.delete("transfer-encoding");

    return request({
      body: bodyPayload,
      headers: props.headers,
    });
  }

this is my proxy/route.ts

import { GeneratedOperation } from "graphql-ops-proxy/lib/proxy";
import { OPERATIONS } from "@/graphql/gql/gql";
import { createEdgeHandler } from "@/app/api/proxy/edge";
import { NextResponse } from "next/server";

export const runtime = "edge";

const handler = createEdgeHandler(
  new URL(`https://graphql.eu.fauna.com/graphql`),
  OPERATIONS as Array<GeneratedOperation>,
  {
    onResponse: (resp: NextResponse, { op, body }) => {
      const headers = new Headers(resp.headers);

      // add cache headers
      if (op.mBehaviour.ttl) {
        headers.append("Cache-Control", "public");
        headers.append("Cache-Control", `s-maxage=${op.mBehaviour.ttl}`);
        headers.append(
          "Cache-Control",
          `stale-while-revalidate=${op.mBehaviour.ttl}`
        );
      }

      headers.append("Content-Type", "application/json");

      return NextResponse.json(body, { headers, status: 200 });
    },
  }
);

export { handler as GET, handler as POST };
ilijaNL commented 1 year ago

@nielll Good to know you found a fix yourself. Actually I fixed this in my other package I made which is really similar to this one but is more generic: https://github.com/ilijaNL/graphql-edge-proxy The readme is lacking but you can find the usage in tests dir (https://github.com/ilijaNL/graphql-edge-proxy/blob/main/tests/store.test.ts)