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

Handler in App router TypeError 'setup' #113

Open
luchillo17 opened this issue Jun 6, 2023 · 12 comments
Open

Handler in App router TypeError 'setup' #113

luchillo17 opened this issue Jun 6, 2023 · 12 comments
Assignees

Comments

@luchillo17
Copy link

Handler in App router TypeError 'setup'

While using Next 13.4.1, tried to use the app router to expose graphql server under app/graphql/route.ts, it gives errors, it does work if I move it to the deprecated pages router under pages/api/graphql.ts, did try the experimental flag on the next.config.js file to no avail.

Code

import { startServerAndCreateNextHandler } from '@as-integrations/next';
import { getApolloServer } from '@graph-meister/neo4j-apollo';
import { NextRequest } from 'next/server';

const typeDefs = `#graphql
   type Movie {
    title: String
    tagline: String
    released: Int
    actors: [Person!]! @relationship(type: "ACTED_IN", direction: IN)
    directors: [Person!]! @relationship(type: "DIRECTED", direction: IN)
  }

  type Person {
    name: String
    born: Int
    movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
  }
`;

const server = await getApolloServer(typeDefs);

const handler = startServerAndCreateNextHandler(server);

export async function GET(request: NextRequest) {
  return handler(request);
}

export async function POST(request: NextRequest) {
  return handler(request);
}

Environment

{
  "name": "",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {},
  "private": true,
  "dependencies": {
    "@apollo/client": "^3.7.15",
    "@apollo/server": "^4.7.1",
    "@as-integrations/next": "^2.0.0",
    "@neo4j/graphql": "^3.20.1",
    "@nx/next": "16.3.0",
    "graphql": "^16.6.0",
    "neo-forgery": "^2.0.1",
    "neo4j-driver": "^5.9.0",
    "next": "13.4.1",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "tslib": "^2.3.0"
  },
  "devDependencies": {
    "@nx/cypress": "16.3.0",
    "@nx/eslint-plugin": "16.3.0",
    "@nx/jest": "16.3.0",
    "@nx/js": "16.3.0",
    "@nx/linter": "16.3.0",
    "@nx/react": "16.3.0",
    "@nx/workspace": "16.3.0",
    "@testing-library/react": "14.0.0",
    "@types/jest": "^29.4.0",
    "@types/node": "18.14.2",
    "@types/react": "18.0.28",
    "@types/react-dom": "18.0.11",
    "@typescript-eslint/eslint-plugin": "^5.58.0",
    "@typescript-eslint/parser": "^5.58.0",
    "babel-jest": "^29.4.1",
    "cypress": "^12.11.0",
    "encoding": "^0.1.13",
    "eslint": "~8.15.0",
    "eslint-config-next": "13.4.1",
    "eslint-config-prettier": "8.1.0",
    "eslint-plugin-cypress": "^2.10.3",
    "eslint-plugin-import": "2.27.5",
    "eslint-plugin-jsx-a11y": "6.7.1",
    "eslint-plugin-react": "7.32.2",
    "eslint-plugin-react-hooks": "4.6.0",
    "jest": "^29.4.1",
    "jest-environment-jsdom": "^29.4.1",
    "jest-environment-node": "^29.4.1",
    "nx": "16.3.0",
    "nx-cloud": "latest",
    "prettier": "^2.6.2",
    "ts-jest": "^29.1.0",
    "ts-node": "10.9.1",
    "typescript": "~5.0.2"
  }
}

Terminal output

- event compiled successfully in 4.9s (1478 modules)
- error TypeError: Cannot read properties of undefined (reading 'setup')
    at RouteHandlerManager.handle (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-handler-managers/route-handler-manager.js:24:16)
    at doRender (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-server.js:935:58)
    at cacheEntry.responseCache.get.incrementalCache.incrementalCache (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-server.js:1161:34)
    at /home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/response-cache/index.js:99:42
    at ResponseCache.get (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/response-cache/index.js:149:11)
    at DevServer.renderToResponseWithComponentsImpl (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-server.js:1080:53)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async DevServer.renderPageComponent (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-server.js:1312:24)
    at async DevServer.renderToResponseImpl (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-server.js:1343:32)
    at async DevServer.pipeImpl (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-server.js:627:25)
    at async Object.fn (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/next-server.js:1136:21)
    at async Router.execute (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/router.js:315:32)
    at async DevServer.runImpl (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-server.js:601:29)
    at async DevServer.run (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/next-dev-server.js:922:20)
    at async DevServer.handleRequestImpl (/home/carlos/Projects/graph-meister/node_modules/.pnpm/next@13.4.1_@babel+core@7.22.1_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-server.js:533:20)```
@martinnabhan
Copy link
Collaborator

Are you sure the server variable's promise is being fulfilled before passing server to startServerAndCreateNextHandler? It looks like you're doing top-level await, which as far as I know isn't supported in Next.js.

@luchillo17
Copy link
Author

It is in experimental flags in the config for webpack, should work based on this comment 2 years back, basically it's webpack that gives the support: vercel/next.js#11185 (comment)

@luchillo17
Copy link
Author

If it were to be the await, why does it work when I move this code to the pages/api/graphql.ts? (of course I have to remove the GET & SET functions).

@luchillo17
Copy link
Author

The biggest difference here would be the export default in the Pages router vs the export of the 2 handlers in the App router, I do believe I followed the steps, could topLevelAwait be having unintended consequences here?
image

@skn437
Copy link

skn437 commented Jun 7, 2023

luchillo17, I have the same problem as you. Page Router works fine when using top level "await". But when I use app router, I get almost the same terminal output as you.

@luchillo17
Copy link
Author

luchillo17 commented Jun 7, 2023

@skn437 Have you tried without the top level await part? I can't remove it because Neo4j generates the schema with a promise so...

@skn437
Copy link

skn437 commented Jun 7, 2023

@skn437 Have you tried without the top level await part? I can't remove it because Neo4j generates the schema with a promise so...

Me as well. I also use Neo4j. It needs "await" to generate Schema. So I can't remove it.

@martinnabhan
Copy link
Collaborator

According to this it seems like top-level await doesn't work in the app directory.

I haven't tried this so it might not work, but you might be able to fulfill the promise when the first request comes in like this:

import { startServerAndCreateNextHandler } from '@as-integrations/next';
import { getApolloServer } from '@graph-meister/neo4j-apollo';
import { NextRequest } from 'next/server';

const typeDefs = `#graphql
   type Movie {
    title: String
    tagline: String
    released: Int
    actors: [Person!]! @relationship(type: "ACTED_IN", direction: IN)
    directors: [Person!]! @relationship(type: "DIRECTED", direction: IN)
  }

  type Person {
    name: String
    born: Int
    movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
  }
`;

let handler = null;
let server = null;

export async function GET(request: NextRequest) {
  if (!server) {
    server = await getApolloServer(typeDefs);
    handler = startServerAndCreateNextHandler(server);
  }

  return handler(request);
}

export async function POST(request: NextRequest) {
  // might need the same code here

  return handler(request);
}

@luchillo17
Copy link
Author

Oh, bit ugly but as long as it does work, so we store the instance on the first available request and reuse it as long as it exists in the global variable.

I wonder if the schemaLink will help as mentioned here: apollographql/apollo-client-nextjs#31 (comment)

@luchillo17
Copy link
Author

luchillo17 commented Jun 9, 2023

It worked perfectly, though I wonder if this could be considered a production-ready setup...

let server: ApolloServer<BaseContext>;
let handler: ReturnType<typeof startServerAndCreateNextHandler>;

const getServerHandler = async () => {
  server ??= await getApolloServer(typeDefs);
  handler ??= startServerAndCreateNextHandler(server);
};

export async function GET(request: NextRequest) {
  await getServerHandler();
  return handler(request);
}

export async function POST(request: NextRequest) {
  await getServerHandler();
  return handler(request);
}

@skn437
Copy link

skn437 commented Jun 9, 2023

Thanks a lot...It works...

@luchillo17
Copy link
Author

Maybe mentioning this in the README for working around top-level await?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants