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

Apollo BatchHttpLink queries failing in React app #4280

Open
dsbw opened this issue Mar 2, 2022 · 0 comments
Open

Apollo BatchHttpLink queries failing in React app #4280

dsbw opened this issue Mar 2, 2022 · 0 comments

Comments

@dsbw
Copy link

dsbw commented Mar 2, 2022

Upgrading an old Apollo client/server setup to use graphql-tools exclusively, BatchHttpLink queries fail with "POST body sent invalid JSON" (network error) and "POST http://localhost:4000/graphql 400 (Bad Request) batchHttpLink.ts:132" (on the console).

We tried a sandbox but it didn't like the apollo imports. :-/

To reproduce, create a basic create-react-app. We have this for our initialization:

import { BatchHttpLink } from "@apollo/client/link/batch-http"
import {
  ApolloClient,
  InMemoryCache,
  ApolloProvider,
  ApolloLink,
  useQuery,
  gql
} from "@apollo/client";
import Assess from './assess'


const link = ApolloLink.from([
  new BatchHttpLink({uri: '[http://localhost:4000/graphql'](http://localhost:4000/graphql%27)})
])


const client = new ApolloClient({
  link,
  cache: new InMemoryCache()
});

function App() {

  return (
    <ApolloProvider client={client}>
      <Assess />  
    </ApolloProvider>
  );
}

export default App;

And we have this for a query page. (It doesn't really seem to matter what query is made or whether it exists on the server.)

import React from 'react'
import {
  useQuery,
  gql
} from "@apollo/client";


const ome_client_assessments = gql`
  query ome_client_assessments($uuid: ID!) {
    client_assessments(uuid: $uuid) {
      id
      name
    }
  }
`

const Assess = () => {
  const { loading, error, data } = useQuery(ome_client_assessments, {
    variables: { user: '12345' }
  })
  return (
    <h1>Assess!</h1>
  )
}

export default Assess

On the backend, we've taken our server (which normally stitches together a bunch of schema based on environment variable settings) and hard-coded a single service. Again, it doesn't seem to matter what this points to because it never gets this far:

const waitOn = require('wait-on');
const express = require('express');
const cors = require('cors');
const {graphqlHTTP} = require('express-graphql');
const {introspectSchema} = require('@graphql-tools/wrap');
const {stitchSchemas} = require('@graphql-tools/stitch');
const {fetch} = require('cross-fetch');
const {print} = require('graphql');

const service_map = {'accounts': {"link": 'http://localhost:3000/graphql'}}

function makeRemoteExecutor(url) {
    return async ({document, variables, context}) => {
        const query = typeof document === 'string' ? document : print(document);
        const fetchResult = await fetch(url, {
            method: 'POST',
            headers: {
                'Auth': context.authHeader,
                'Content-Type': 'application/json',
                "x-api-token": '2ade0bbe320ed0529cec2cfc9f224f57',
            },
            body: JSON.stringify({query, variables}),
        });
        return fetchResult.json();
    };
}

async function makeGatewaySchema() {
    const submap = []
    for (const key in service_map) {
        let executor = makeRemoteExecutor(service_map[key]['link'])
        submap.push({
            schema: await introspectSchema(executor, {}),
            batch: true, //Not sure if this actually does anything...
            executor: executor
        })
    }

    return stitchSchemas({
            subschemas: submap,
        }
    );
}

waitOn({resources: []}, async () => {
    const schema = await makeGatewaySchema();
    const app = express();
    app.use(cors());
    app.use('/graphql', graphqlHTTP((req) => ({
        schema,
        context: {authHeader: req.headers.auth},
        graphiql: {headerEditorEnabled: true},
    })));
    app.listen(4000, () => console.log('gateway running at http://localhost:4000/graphql'));
});

If we use a regular HttpLink on the client, our code works (or returns the expected errors from the service), whereas BatchHttpLink gives us the "POST body sent invalid JSON" error.

These behaviors show up when everything is running on a single Mac, PC or in a kubernetes pod hosted on AWS. Node versions are 12, 15 and 16. React version is 17.0.2 and create-react-app is 5.0.0. Using these graphql libraries:

   "@graphql-tools/batch-delegate": "^8.2.4",
    "@graphql-tools/delegate": "^8.5.0",
    "@graphql-tools/schema": "^7.0.0",
    "@graphql-tools/stitch": "^7.0.4",
    "@graphql-tools/wrap": "^7.0.1",
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

1 participant