"Troubleshooting the inconsistency of GraphQL resolver context functionality between Playground and the client in the official NextJS starter

Currently, I am making adjustments to my NextJS/Apollo application to enable SSG with GraphQL API routes. I have referenced this official NextJS starter example as a foundation for configuring the client.

An issue arose in my application which led me to go back to the starter example to try and replicate it, successfully. The problem arises when a context object is introduced to the query resolvers. Surprisingly, everything functions correctly without the context object (in both the playground and client). However, once a context object is incorporated and passed to the resolvers, it works properly in the playground but the context object is undefined when triggered from the client. Below is the code snippet from the official NextJS starter example with my annotations:

graphql.js

import { ApolloServer } from "apollo-server-micro";
import { schema } from "../../apollo/schema";

const apolloServer = new ApolloServer({
    schema,
    context: {        // 
        foo: "bar",   // this is the context object I've added
    },                //
});

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

export default apolloServer.createHandler({ path: "/api/graphql" });

typedefs.js

import { gql } from '@apollo/client'

export const typeDefs = gql`
  type User {
    id: ID!
    name: String!
    status: String!
  }

  type Query {
    viewer: User
  }
`

Despite receiving the correct response when querying the API in the GraphQL playground and seeing the context foo: bar object in the console log in the server, the context object returns undefined in the browser when visiting the index page, as shown below:

index.js

import gql from "graphql-tag";
import Link from "next/link";
import { useQuery } from "@apollo/client";
import { initializeApollo } from "../apollo/client";

const ViewerQuery = gql`
    query ViewerQuery {
        viewer {
            id
            name
            status
        }
    }
`;

const Index = () => {
    const {
        data: { viewer },
    } = useQuery(ViewerQuery);

    return (
        <div>
            You're signed in as {viewer.name} and you're {viewer.status} goto{" "}
            <Link href="/about">
                <a>static</a>
            </Link>{" "}
            page.
        </div>
    );
};

export async function getStaticProps() {
    const apolloClient = initializeApollo();

    await apolloClient.query({
        query: ViewerQuery,
    });

    return {
        props: {
            initialApolloState: apolloClient.cache.extract(),
        },
    };
}

export default Index;

Although the viewer name and status are correctly rendered, the console log for the context object displays undefined. This discrepancy is intriguing, especially considering this is an official NextJS starter example. I am unsure why the client setup may not be accepting context in the resolvers. If this is indeed the issue, I am curious if there are other official examples with a client setup that does support resolver context input.

While this is quite a lengthy query, here is the snippet for client.js:

import { useMemo } from "react";
import { ApolloClient, InMemoryCache } from "@apollo/client";

let apolloClient;

function createIsomorphLink() {
    if (typeof window === "undefined") {
        const { SchemaLink } = require("@apollo/client/link/schema");
        const { schema } = require("./schema");
        return new SchemaLink({ schema });
    } else {
        const { HttpLink } = require("@apollo/client/link/http");
        return new HttpLink({
            uri: "http://localhost:3000/api/graphql",
            credentials: "same-origin",
        });
    }
}

function createApolloClient() {
    return new ApolloClient({
        ssrMode: typeof window === "undefined",
        link: createIsomorphLink(),
        cache: new InMemoryCache(),
    });
}

export function initializeApollo(initialState = null) {
    const _apolloClient = apolloClient ?? createApolloClient();

    // If your page has Next.js data fetching methods that use Apollo Client, the initial state
    // gets hydrated here
    if (initialState) {
        _apolloClient.cache.restore(initialState);
    }
    // For SSG and SSR always create a new Apollo Client
    if (typeof window === "undefined") return _apolloClient;
    // Create the Apollo Client once in the client
    if (!apolloClient) apolloClient = _apolloClient;

    return _apolloClient;
}

export function useApollo(initialState) {
    const store = useMemo(() => initializeApollo(initialState), [initialState]);
    return store;
}

If anyone can clone this official repository and provide insights on how to resolve the context issue in the client, or if there are other client setups that accept resolver context, I welcome your input. This problem has been puzzling me for the past two days!

Answer №1

The issue has been identified. The client configuration utilizes SchemaLink for the HTTP request. The context is provided to the SchemaLink constructor function, rather than in the server options. This is because the context is transmitted in the HTTP headers via httpLink.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

React - Updating state from an external component

I realize that the question I am about to ask may go against some basic principles of using React... however, with this example, I hope someone can assist me in finding a solution to the problem I am currently facing. While this code snippet is not from m ...

Encountering an abundance of concurrent requests using NodeJS and request-promise

I am currently working on a NodeJS project that involves a large array of about 9000 elements containing URLs. These URLs need to be requested using the "request-promise" package. However, making 9000 concurrent GET requests to the same website from the sa ...

Tips for adjusting the height of MUI Date Picker to fit your preferences

<Box sx={{ m: 1 }}> <LocalizationProvider dateAdapter={AdapterDayjs}> <DatePicker label="Enter Date" slotProps={{ textField: { height: "10px" } }} ...

What steps should I take to generate a stylized date input in javascript?

Looking to dynamically create a date string in JavaScript with the following format: dd-MMM-yyyy Need the dd part to change between 1 and 29 each time I generate the variable within a loop Month (MMM) should be set as Jan ...

While typing, React-hook-form is removing the input field when the mode property is enabled

Currently, I am implementing a basic form using react-hook-form version 7 along with Material UI. However, I have encountered an unusual behavior when configuring the mode in useForm({mode: ".."}). Below is a snippet of my code: import { yupResol ...

There was a problem with the WebSocket handshake: the response header value for 'Sec-WebSocket-Protocol' did not match any of the values sent

I've encountered an issue with my React project that involves streaming live video through a WebSocket. Whenever the camera firmware is updated, I face an error in establishing the WebSocket connection. Here's how I initiate the WebSocket: wsRe ...

How can I implement a scroll functionality to navigate to the next item in a Vuetify v-carousel?

I'm currently working on a front page layout using the v-carousel component and I am looking to achieve automatic scrolling to the next item without the need for arrows or delimiters. How can I make this happen? Below is my current code: <template ...

Understanding the concept of mutable properties in Typescript

Why can the property 'name' in the class 'PersonImpl' be reassigned even though it is not declared as read-only in the Person interface? interface Person { readonly name: string; } interface Greeting extends Person { greet( ...

Registering components globally in Vue using the <script> tag allows for seamless integration

I'm currently diving into Vue and am interested in incorporating vue-tabs into my project. The guidelines for globally "installing" it are as follows: //in your app.js or a similar file // import Vue from 'vue'; // Already available imp ...

Implementing NextJS server-side rendering and static site generation after a user signs in or while making updates to

Having some experience with ReactJS, I am now delving into NextJS. A burning question keeps resurfacing in my mind about SSR/SSG. In the context of an e-commerce application where all pages (/products, /product, etc.) are either SSGed or SSRed, what happen ...

In JavaScript, ensure to directly use the value of a variable when defining an asynchronous function, rather than by reference

Hello there, Let me paint you a picture: for (j = 0; j < btnArr.length; j++) { var btn = document.createElement("button"); btn.addEventListener("click", function() { press(this, j) }, false); div.appendChild(btn); } The issue at hand is t ...

Tips for restricting users from inputting spaces into a form field using ReactJS

Within my application, I have developed a specialized component named QueryForm that serves the purpose of enabling search capabilities. The code snippet being outputted by this component is as follows: ...

What steps should I take to adjust the price when multiple items are chosen?

I am working on a school project that requires JavaScript programming assistance. You can view the code here: https://jsfiddle.net/zvov1jpr/3/ HTML: <script src="java.js"></script> <div id="formular"> <div id=&qu ...

Issues with jwplayer functionality

After downloading the necessary files and carefully following all instructions, I am still experiencing issues with the player not functioning as expected. <code> <html> <head> <script type="text/javascript" src="/jwpl ...

Issue encountered while subscribing to SalesForce topic using Node.js

Attempting to subscribe to a SalesForce topic through a Node.js server using the code provided in the JSForce documentation: conn.streaming.topic("InvoiceStatementUpdates").subscribe(function(message) { console.log('Event Type : ' + message.ev ...

Failed to connect to Wordpress REST API when calling it from a NextJS server due to ECONNREFUSED error

I am currently working on a basic example that involves fetching a list of page slugs from the WordPress REST API, but I am encountering some unexpected behavior. My getPageList() function is an asynchronous function that makes a simple call to the WP API ...

Creating metadata for a node/npm module build

Looking for a solution to output JSON with build date and updated minor version number using grunt and requirejs for our application. It seems like this would be a common requirement. Any existing tools that can achieve this? ...

The behavior exhibited by node.js express is quite peculiar

I am currently running an Express server. My process involves uploading an Excel File from HTML, which is then parsed by Express to perform calculations. Each row in the Excel file contains information about a User's address. For each address, our ...

Prevent further clicking on a button in a custom Drupal module after it has been clicked three times

I'm new to using Drupal and have created a custom module similar to webform. In my module page, I have two submit buttons and 2 textboxes as shown below: function contact_request($form, &$form_state) { $form ['info'] =array( &ap ...

Adding a line and text as a label to a rectangle in D3: A step-by-step guide

My current bar graph displays values for A, B, and C that fluctuate slightly in the data but follow a consistent trend, all being out of 100. https://i.stack.imgur.com/V8AWQ.png I'm facing issues adding lines with text to the center of each graph. A ...