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

Issue with Apollo Server API (404 Error and no JSON Fetching work) #56

Closed
sustainjane98 opened this issue Feb 7, 2021 · 2 comments
Closed

Comments

@sustainjane98
Copy link

sustainjane98 commented Feb 7, 2021

Problematic behavior

I created an API that serves an Apollo-Server with an Query. When I test it with your library it returns 404 Not Found and I can't access the Response Data json without invalid json error.

await testApiHandler({
    requestPatcher: (req) => {
      req.headers = {
        ...req.headers,
        Origin: "localhost:3000",
        Host: "localhost:3000",
      };
    },
    handler: graphQlHandler,
    test: async ({ fetch }) => {
      const query = `query getYoutubeVideoMetadata($youtubeVideoId: String!) {
  videoData: youtubeVideoMeadata(youtubeVideoId: $youtubeVideoId) {
    id
    title
    thumbnails {
      default {
        url
      }
    }
  }
}
`;
      const res = await fetch({
        method: "POST",
        headers: {
          Accept: "	*/*",
          "Accept-Encoding":
            "gzip deflate",
          "Accept-Language":
            "de,en-US;q=0.7,en;q=0.3",
          "Content-Type":
            "application/json",
          "User-Agent":
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:85.0) Gecko/20100101 Firefox/85.0",
        },
        body: JSON.stringify({
          operationName:
            "getYoutubeVideoMetadata",
          query,
          variables: {
            youtubeVideoId: exampleYoutubeVideoId,
          },
        }),
      });
      console.log(await res.json());
    },
  });
Expected behavior
Reproduction steps
  1. Start Jest Test against API.
  2. Return JSOnN Data from Query.
  3. Successful Resolve them and get 200 or so.
Runtime environment
  • OS: windows/mac os
  • Browser: firefox 71, chrome 90
  • Version: v1.2.3
  • Node version: 14
  • Babel: yes, version 7
  • TypeScript project: yes
Additional context
@Xunnamius Xunnamius added the bug Something isn't working label Feb 7, 2021
@Xunnamius Xunnamius removed the bug Something isn't working label Feb 7, 2021
@Xunnamius
Copy link
Owner

Two things:

  1. You cannot use Next's body parser and Apollo at the same time. Use custom configuration to disable the body parser.

  2. Apollo checks if request.url matches the path originally passed to the ApolloServer.createHandler function. However, NTARH's fetch function always uses "/" as request.url. To change request.url to what it should be, use requestPatcher.

Here is an example test file that you can drop into the official Next.js Apollo example repo and run with jest. The test passes:

import { testApiHandler } from 'next-test-api-route-handler';
import handler, { config } from '../pages/api/graphql';

// ? This is the configuration that tells Next not to use body parser
handler.config = config;

describe('my-test', () => {
  it('does what I want', async () => {
    expect.hasAssertions();

    await testApiHandler({
      requestPatcher: (req) => (req.url = '/api/graphql'),
      handler,
      test: async ({ fetch }) => {
        const query = `query ViewerQuery {
          viewer {
            id
            name
            status
          }
        }`;

        const res = await fetch({
          method: 'POST',
          headers: {
            'content-type': 'application/json'
          },
          body: JSON.stringify({
            query
          })
        });

        expect(await res.json()).toStrictEqual({
          data: { viewer: { id: '1', name: 'John Smith', status: 'cached' } }
        });
      }
    });
  });
});

This seems like good knowledge to add to the README, thanks! And feel free to reply if you're still experiencing issues.

@sustainjane98
Copy link
Author

Thanks a lot for your help seems like the Issue was the requestPatcher: (req) => (req.url = '/api/graphql') thing, however I now got and timeout in jest which seems like it is never really resolved...

test("Fetch Metadata For Example YoutubeVideo", async () => {
  jest.setTimeout(30000);
  await testApiHandler({
    requestPatcher: (req) =>
      (req.url = "/api/graphql"),
    handler: graphQlHandler,
    test: async ({ fetch }) => {
      const query = `{
  videoData: youtubeVideoMeadata(youtubeVideoId: ${exampleYoutubeVideoId}) {
    id
    title
    thumbnails {
      default {
        url
      }
    }
  }
}
`;
      const res = await fetch({
        method: "POST",
        headers: {
          "Content-Type":
            "application/json",
        },
        body: JSON.stringify({
          query,
        }),
      });
      console.log(await res.json());
    },
  });
});
// Template from: https://stackoverflow.com/questions/62105419/next-js-api-routes-with-type-graphql-error-resolver-is-not-a-function
import "reflect-metadata";
import { ApolloServer } from "apollo-server-micro";
import { buildSchema } from "type-graphql";
import {
  NextApiRequest,
  NextApiResponse,
} from "next";
import YoutubeResolver from "../../graphql/youtube.resolver";

let apolloServerHandler: (
  req: any,
  res: any,
) => Promise<void>;

const getApolloServerHandler = async () => {
  if (!apolloServerHandler) {
    const schema = await buildSchema({
      resolvers: [YoutubeResolver],
    });
    apolloServerHandler = new ApolloServer(
      { schema },
    ).createHandler({
      path: "/api/graphql",
    });
  }
  return apolloServerHandler;
};

export default async (
  req: NextApiRequest,
  res: NextApiResponse,
) => {
  const apolloServerHandler = await getApolloServerHandler();
  return apolloServerHandler(req, res);
};

export const config = {
  api: { bodyParser: false },
};

Maybe this is a reason of my hacky solution to make the async buildSchema from typegraphql work in sync environment.
As far as I know the libary would call the handler I provide with mock req, res objects. So then it would call an method which itself provides the actual apollo server, which could cause an Promise never resolved Issue of some kind. Maybe you have an Idea.

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

2 participants