Skip to content
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

NextJS 13+ (app/api/graphql/route.js) Integration #2696

Closed
bahmanworld opened this issue Apr 19, 2023 · 17 comments · Fixed by #2760
Closed

NextJS 13+ (app/api/graphql/route.js) Integration #2696

bahmanworld opened this issue Apr 19, 2023 · 17 comments · Fixed by #2760

Comments

@bahmanworld
Copy link

bahmanworld commented Apr 19, 2023

I wanna integrate graphql-yoga with nextjs 13 in app/api/graphql/route.js.
Is there any way to do that?

I've tried some tricks before but i've got no answer:

import { createSchema, createYoga } from 'graphql-yoga'
import { NextRequest } from 'next/server'

const schema = createSchema({
    typeDefs: /* GraphQL */ `
    type Query {
        hello: String!
    }
    `,
    resolvers: {
        Query: {
            hello: () => 'Hello World!'
        }
    }
})

const yoga = createYoga({
    schema: schema,
    graphqlEndpoint: '/api/graphql'
})

export const GET = async (request: NextRequest) => {
    return await yoga({ request })
}

or

import { createSchema, createYoga } from 'graphql-yoga'

const schema = createSchema({
    typeDefs: /* GraphQL */ `
    type Query {
        hello: String!
    }
    `,
    resolvers: {
        Query: {
            hello: () => 'Hello World!'
        }
    }
})

const yoga = createYoga({
    schema: schema,
    graphqlEndpoint: '/api/graphql'
})

export default yoga
@ardatan
Copy link
Collaborator

ardatan commented Apr 19, 2023

Did you try the following;

export {
 yoga as GET,
 yoga as POST
};

Also as far as I see, our nextjs example still works;
https://github.com/dotansimha/graphql-yoga/blob/main/examples/nextjs/pages/api/graphql.ts

@bahmanworld
Copy link
Author

bahmanworld commented Apr 19, 2023

Did you try the following;

export {
 yoga as GET,
 yoga as POST
};

thanks @ardatan
i tried, still doesn't work.

Screenshot 2023-04-19 at 12 55 55 PM

@ardatan
Copy link
Collaborator

ardatan commented Apr 19, 2023

Could you share a reproduction on CodeSandbox or StackBlitz? Thanks!

@bahmanworld
Copy link
Author

bahmanworld commented Apr 19, 2023

Could you share a reproduction on CodeSandbox or StackBlitz? Thanks!

Here the CodeSandBox share link:
🌎 Live Website: nextjs 13 codesandbox project + graphql-yoga

🔴 I guess graphql-yoga isn't compatible with nextjs@13 with new app folder and routing system
🟢 https://us3oz2-3000.csb.app/api/hello route works fine
🟡 i already tried graphql-yoga on nextjs@13 without app folder and it works fine

@mmahalwy
Copy link

Running into the same problem as well :(

@mmahalwy
Copy link

The way to solve is:

export async function POST(request: Request) {
  const result = await yoga.fetch(request.url, {
    method: 'POST',
    headers: request.headers,
    body: await request.text(),
  });

  return new Response(result.body, {
    status: result.status,
    headers: result.headers,
  });
}

@ardatan
Copy link
Collaborator

ardatan commented Apr 26, 2023

Could you add fetchAPI: { Response } and try again?

import { createYoga, createSchema } from 'graphql-yoga'

const yoga = createYoga({
    graphqlEndpoint: '/api/graphql',
    schema: createSchema({
        typeDefs: /* GraphQL */ `
      type Query {
        greetings: String
      }
    `,
        resolvers: {
            Query: {
                greetings: () =>
                    'This is the `greetings` field of the root `Query` type',
            },
        },
    }),
    fetchAPI: {
        Response: Response
    }
})

export {
    yoga as GET,
    yoga as POST,
}

@thai-recurmetrics
Copy link

@ardatan your example works great locally. However, when deployed to Amplify, I got the following error:

2023-05-06T14:55:56.782Z [WARNING]: src/app/api/graphql/route.ts
Type error: Route "src/app/api/graphql/route.ts" has an invalid "GET" export:
Type "{ request: Request; } & Partial<{}>" is not a valid type for the function's first argument.
Expected "Request | NextRequest", got "{ request: Request; } & Partial<{}>".

Any idea how to address this?

@EmrysMyrddin
Copy link
Collaborator

EmrysMyrddin commented May 12, 2023

@thai-recurmetrics This is because it seems Next compiler doesn't check for routes export types on dev mode.

Export yoga.handleRequest instead of yoga should fix the typing issue :

import { createYoga, createSchema } from 'graphql-yoga'

const { handleRequest } = createYoga({
  graphqlEndpoint: '/api/graphql',
  schema: createSchema({
    typeDefs: /* GraphQL */ `
      type Query {
        greetings: String
      }
    `,
    resolvers: {
      Query: {
        greetings: () =>
          'This is the `greetings` field of the root `Query` type',
      },
    },
  }),
  fetchAPI: {
    Response: Response,
    Request: Request,
  },
})

export { handleRequest as GET, handleRequest as POST }

@bahmanworld
Copy link
Author

@thai-recurmetrics This is because it seems Next compiler doesn't check for routes export types on dev mode.

Export yoga.handleRequest instead of yoga should fix the typing issue :

import { createYoga, createSchema } from 'graphql-yoga'

const { handleRequest } = createYoga({
  graphqlEndpoint: '/api/graphql',
  schema: createSchema({
    typeDefs: /* GraphQL */ `
      type Query {
        greetings: String
      }
    `,
    resolvers: {
      Query: {
        greetings: () =>
          'This is the `greetings` field of the root `Query` type',
      },
    },
  }),
  fetchAPI: {
    Response: Response,
    Request: Request,
  },
})

export { handleRequest as GET, handleRequest as POST }

It works great!
thanks @EmrysMyrddin

@thai-recurmetrics
Copy link

@bahmanworld thanks for the example! I actually got it working.

This was referenced May 7, 2024
This was referenced May 23, 2024
@FullstackWEB-developer
Copy link

FullstackWEB-developer commented Jun 26, 2024

I have implemented graphql server with nextjs 14 app router

src\app\api\graphql\route.ts

import { createYoga } from 'graphql-yoga'
import type { NextApiRequest, NextApiResponse } from 'next'

import schema from './schema'

const { handleRequest } = createYoga<{
  req: NextApiRequest
  res: NextApiResponse
}>({
  schema,
  // While using Next.js file convention for routing, we need to configure Yoga to use the correct endpoint
  graphqlEndpoint: process.env.GRAPHQL_END_POINT,
  // Yoga needs to know how to create a valid Next response
  fetchAPI: { Response }
})

export { handleRequest as GET, handleRequest as POST };

@Danubius1st
Copy link

Danubius1st commented Oct 28, 2024

.next/types/app/api/graphql/route.ts:49:7
Type error: Type '{ tag: "GET"; param_position: "second"; param_type: { req: NextApiRequest; res: NextApiResponse; } & Partial; }' does not satisfy the constraint 'ParamCheck'.
Types of property 'param_type' are incompatible.
Property 'params' is missing in type '{ req: NextApiRequest; res: NextApiResponse; } & Partial' but required in type 'RouteContext'.

package.json:

{
...
  "dependencies": {
...
    "graphql": "^16.9.0",
    "graphql-scalars": "^1.23.0",
    "graphql-yoga": "^5.7.0",
...
    "next": "15.0.1",
...
  },
  "devDependencies": {
    "@types/node": "^22.8.1",
    "@types/react": "^18.3.12",
    "@types/react-dom": "^18.3.1",
    "eslint": "^9.13.0",
    "eslint-config-next": "15.0.1",
    "prisma": "^5.21.1",
    "typescript": "^5.6.3"
  }
}

Doesn't work with Next.js 15.
Up to version 14.

@simpleneeraj
Copy link

.next/types/app/api/graphql/route.ts:49:7 Type error: Type '{ tag: "GET"; param_position: "second"; param_type: { req: NextApiRequest; res: NextApiResponse; } & Partial; }' does not satisfy the constraint 'ParamCheck'. Types of property 'param_type' are incompatible. Property 'params' is missing in type '{ req: NextApiRequest; res: NextApiResponse; } & Partial' but required in type 'RouteContext'.

package.json:

{
...
  "dependencies": {
...
    "graphql": "^16.9.0",
    "graphql-scalars": "^1.23.0",
    "graphql-yoga": "^5.7.0",
...
    "next": "15.0.1",
...
  },
  "devDependencies": {
    "@types/node": "^22.8.1",
    "@types/react": "^18.3.12",
    "@types/react-dom": "^18.3.1",
    "eslint": "^9.13.0",
    "eslint-config-next": "15.0.1",
    "prisma": "^5.21.1",
    "typescript": "^5.6.3"
  }
}

Doesn't work with Next.js 15. Up to version 14.

Issue Description

In setting up a GraphQL API with Next.js 15's route handlers and GraphQL Yoga, I initially encountered a type error. The error stemmed from a mismatch between Next.js's route handler types and the expected types within GraphQL Yoga’s handleRequest function. Specifically, the error mentioned that the param_type in the GET handler did not satisfy the ParamCheck constraint, pointing to a missing params property required by RouteContext.

Steps Taken to Fix

  1. Configured GraphQL Yoga:
    I set up the GraphQL server using graphql-yoga and configured it with various plugins, including those from @escape.tech/graphql-armor-*(optional) to ensure security features such as query cost limiting and depth checking. Here’s the configuration:

    import { createYoga } from 'graphql-yoga';
    import { costLimitPlugin } from '@escape.tech/graphql-armor-cost-limit';
    import { maxAliasesPlugin } from '@escape.tech/graphql-armor-max-aliases';
    import { maxDepthPlugin } from '@escape.tech/graphql-armor-max-depth';
    import { maxDirectivesPlugin } from '@escape.tech/graphql-armor-max-directives';
    import { maxTokensPlugin } from '@escape.tech/graphql-armor-max-tokens';
    import { useDisableIntrospection as disableIntrospection } from '@graphql-yoga/plugin-disable-introspection';
    import schema from './schema';
    
    const isDevelopment = process.env.NODE_ENV === 'development';
    const allowedOrigins = process.env.ALLOWED_URLS!.split(',')!;
    
    export const { handleRequest } = createYoga({
      schema,
      fetchAPI: { Response },
      graphqlEndpoint: '/api/graphql',
      plugins: [
        costLimitPlugin({}),
        maxTokensPlugin({ n: 1000 }),
        maxDepthPlugin({ n: 10 }),
        maxDirectivesPlugin(),
        maxAliasesPlugin(),
        disableIntrospection({ isDisabled: () => !isDevelopment }),
      ],
      graphiql: isDevelopment,
      multipart: false,
      cors: (request) => {
        const requestOrigin = request.headers.get('origin');
        const isOriginAllowed = allowedOrigins.includes(requestOrigin!);
        return {
          origin: isOriginAllowed ? requestOrigin! : '',
          credentials: true,
          methods: ['GET', 'POST'],
        };
      },
    });
  2. Set Up Route Handlers in Next.js:
    To enable GraphQL queries via GET and POST requests in Next.js 15, I defined route handlers in /app/api/graphql/route.ts. Originally, these handlers were as follows:

    import { handleRequest } from '@/server/graphql';
    import { NextRequest } from 'next/server';
    
    type ContextType = any;
    
    export const GET = (req: NextRequest, context: ContextType) =>
      handleRequest(req, context);
    
    export const POST = (req: NextRequest, context: ContextType) =>
      handleRequest(req, context);
  3. Resolved Type Mismatch with Standard Route Handlers:
    Next.js route handlers expect specific typings, which caused the initial issue. I adjusted the route handlers by adding a minimal context parameter and ensuring compatibility with Next.js route handler conventions. Here’s the updated route.ts that worked:

    import { NextRequest } from 'next/server';
    import { handleRequest } from '@/server/graphql';
    
    export const GET = (req: NextRequest) => handleRequest(req);
    export const POST = (req: NextRequest) => handleRequest(req);
  4. Ensured Compatibility with Next.js:
    Finally, I confirmed that handleRequest correctly processed requests from Next.js without requiring further customizations in RouteContext.

Additional Information

Environment:

  • Next.js: 15.0.3
  • graphql-yoga: ^5.8.0
  • @escape.tech/graphql-armor- plugins*: Various plugins for additional security
  • TypeScript: ^5

This setup should work well for integrating GraphQL in Next.js 15 with robust type safety and secure query handling.

@simpleneeraj
Copy link

Issue Description

In setting up a GraphQL API with Next.js 15's route handlers and GraphQL Yoga, I initially encountered a type error. The error stemmed from a mismatch between Next.js's route handler types and the expected types within GraphQL Yoga’s handleRequest function. Specifically, the error mentioned that the param_type in the GET handler did not satisfy the ParamCheck constraint, pointing to a missing params property required by RouteContext.

Steps Taken to Fix

  1. Configured GraphQL Yoga:
    I set up the GraphQL server using graphql-yoga and configured it with various plugins, including those from @escape.tech/graphql-armor-*(optional) to ensure security features such as query cost limiting and depth checking. Here’s the configuration:

    import { createYoga } from 'graphql-yoga';
    import { costLimitPlugin } from '@escape.tech/graphql-armor-cost-limit';
    import { maxAliasesPlugin } from '@escape.tech/graphql-armor-max-aliases';
    import { maxDepthPlugin } from '@escape.tech/graphql-armor-max-depth';
    import { maxDirectivesPlugin } from '@escape.tech/graphql-armor-max-directives';
    import { maxTokensPlugin } from '@escape.tech/graphql-armor-max-tokens';
    import { useDisableIntrospection as disableIntrospection } from '@graphql-yoga/plugin-disable-introspection';
    import schema from './schema';
    
    const isDevelopment = process.env.NODE_ENV === 'development';
    const allowedOrigins = process.env.ALLOWED_URLS!.split(',')!;
    
    export const { handleRequest } = createYoga({
      schema,
      fetchAPI: { Response },
      graphqlEndpoint: '/api/graphql',
      plugins: [
        costLimitPlugin({}),
        maxTokensPlugin({ n: 1000 }),
        maxDepthPlugin({ n: 10 }),
        maxDirectivesPlugin(),
        maxAliasesPlugin(),
        disableIntrospection({ isDisabled: () => !isDevelopment }),
      ],
      graphiql: isDevelopment,
      multipart: false,
      cors: (request) => {
        const requestOrigin = request.headers.get('origin');
        const isOriginAllowed = allowedOrigins.includes(requestOrigin!);
        return {
          origin: isOriginAllowed ? requestOrigin! : '',
          credentials: true,
          methods: ['GET', 'POST'],
        };
      },
    });
  2. Set Up Route Handlers in Next.js:
    To enable GraphQL queries via GET and POST requests in Next.js 15, I defined route handlers in /app/api/graphql/route.ts. Originally, these handlers were as follows:

    import { handleRequest } from '@/server/graphql';
    import { NextRequest } from 'next/server';
    
    type ContextType = any;
    
    export const GET = (req: NextRequest, context: ContextType) =>
      handleRequest(req, context);
    
    export const POST = (req: NextRequest, context: ContextType) =>
      handleRequest(req, context);
  3. Resolved Type Mismatch with Standard Route Handlers:
    Next.js route handlers expect specific typings, which caused the initial issue. I adjusted the route handlers by adding a minimal context parameter and ensuring compatibility with Next.js route handler conventions. Here’s the updated route.ts that worked:

    import { NextRequest } from 'next/server';
    import { handleRequest } from '@/server/graphql';
    
    export const GET = (req: NextRequest) => handleRequest(req);
    export const POST = (req: NextRequest) => handleRequest(req);
  4. Ensured Compatibility with Next.js:
    Finally, I confirmed that handleRequest correctly processed requests from Next.js without requiring further customizations in RouteContext.

Additional Information

Environment:

  • Next.js: 15.0.3
  • graphql-yoga: ^5.8.0
  • @escape.tech/graphql-armor- plugins*: Various plugins for additional security
  • TypeScript: ^5

This setup should work well for integrating GraphQL in Next.js 15 with robust type safety and secure query handling.

@Urigo
Copy link
Collaborator

Urigo commented Nov 26, 2024

Thank you for your detailed description @simpleneeraj

We solved it a bit differently here - what do you think about that solution, does that work for you?

@simpleneeraj
Copy link

Thank you for your detailed description @simpleneeraj

We solved it a bit differently here - what do you think about that solution, does that work for you?

Yes

@bahmanworld bahmanworld changed the title NextJS 13 (app/api/graphql/route.js) Integration NextJS 13+ (app/api/graphql/route.js) Integration Nov 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment