Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

We're moving the community! Starting July 7, the current community will be read-only for approx. 2 weeks. You can browse content, but posting will be temporarily unavailable. Learn more

InternalServerError: Failed to make Shopify HTTP request: FetchError: invalid json response body

Solved

InternalServerError: Failed to make Shopify HTTP request: FetchError: invalid json response body

g3misa
Shopify Partner
24 5 15

Hi,

 

I am trying to create my first embedded admin app and everything seems to be working fine with API version

"2021-04".

 

However, when i switch to API version "2021-10", I get an INTERNAL SERVER ERROR on this request as my app tries to load:

 

https://cf93-47-155-234-31.ngrok.io/auth/callback?code=69a908234e220f32a5bddfe32c6b11f1&hmac=cdc672a2cb88c7213e191734fda314c6ffa919aa3a5a51255959ccc80e44514b&host=c29jaWFsLWNvbW1lcmNlLWRlbW8ubXlzaG9waWZ5LmNvbS9hZG1pbg&shop=g3-demo.myshopify.com&state=185784368861671&timestamp=1641087145

 

 

The Node error on my terminal is this:

 

InternalServerError: Failed to make Shopify HTTP request: FetchError: invalid json response body at https://g3-demo.myshopify.com/admin/api/undefined/graphql.json reason: Unexpected end of JSON input
┃       at Object.throw (/Users/gmisa/Dev/g3-demo/node_modules/koa/lib/context.js:97:11)
┃       at /Users/gmisa/Dev/g3-demo/node_modules/@shopify/koa-shopify-auth/dist/src/auth/index.js:102:42
┃       at step (/Users/gmisa/Dev/g3-demo/node_modules/tslib/tslib.js:133:27)
┃       at Object.throw (/Users/gmisa/Dev/g3-demo/node_modules/tslib/tslib.js:114:57)
┃       at rejected (/Users/gmisa/Dev/g3-demo/node_modules/tslib/tslib.js:105:69)
┃       at runMicrotasks (<anonymous>)
┃       at processTicksAndRejections (internal/process/task_queues.js:97:5)

 

 

Seems like there is "undefined" in the URL:

 

https://g3-demo.myshopify.com/admin/api/undefined/graphql.json

 

 

This only happens on API version "2021-10" and "2022-01".  Previous API versions work just fine.  Hope someone can help.  Thank you!

 

Here is my _app.js:

 

import { ApolloClient, HttpLink, ApolloProvider, InMemoryCache } from "@apollo/client";
import App from "next/app";
import { AppProvider } from "@shopify/polaris";
import { Provider, useAppBridge } from "@shopify/app-bridge-react";
import { authenticatedFetch } from "@shopify/app-bridge-utils";
import { Redirect } from "@shopify/app-bridge/actions";
import { store, persistor } from '../modules/store';
import { Provider as ReduxProvider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { compose } from 'redux';
import "@shopify/polaris/dist/styles.css";
import translations from "@shopify/polaris/locales/en.json";

function userLoggedInFetch(app) {
  const fetchFunction = authenticatedFetch(app);

  return async (uri, options) => {
    const response = await fetchFunction(uri, options);

    if (
      response.headers.get("X-Shopify-API-Request-Failure-Reauthorize") === "1"
    ) {
      const authUrlHeader = response.headers.get(
        "X-Shopify-API-Request-Failure-Reauthorize-Url"
      );

      const redirect = Redirect.create(app);
      redirect.dispatch(Redirect.Action.APP, authUrlHeader || `/auth`);
      return null;
    }
    return response;
  };
}

function MyProvider(props) {
  const app = useAppBridge();
  const fetchOptions = {
    credentials: "include"
  };
  const link = new HttpLink({ fetch: userLoggedInFetch(app), fetchOptions });

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

  const Component = props.Component;

  return (
    <ApolloProvider client={client}>
      <Component {...props} />
    </ApolloProvider>
  );
}

class MyApp extends App {
  render() {
    const { Component, pageProps, host } = this.props;
    return (
      <AppProvider i18n={translations}>
        <Provider
          config={{
            apiKey: API_KEY,
            host: host,
            forceRedirect: true,
          }}
        >
          <ReduxProvider store={store}>
            <PersistGate persistor={persistor}>
              <MyProvider Component={Component} {...pageProps} />
            </PersistGate>
          </ReduxProvider>
        </Provider>
      </AppProvider>
    );
  }
}

MyApp.getInitialProps = async ({ ctx }) => {
  return {
    host: ctx.query.host,
  };
};

export default MyApp;

 

 

Here's my server.js:

 

import "@babel/polyfill";
import dotenv from "dotenv";
import "isomorphic-fetch";
import createShopifyAuth, { verifyRequest } from "@shopify/koa-shopify-auth";
import Shopify, { ApiVersion } from "@shopify/shopify-api";
import Koa from "koa";
import next from "next";
import Router from "koa-router";

dotenv.config();
const port = parseInt(process.env.PORT, 10) || 8081;
const dev = process.env.NODE_ENV !== "production";
const app = next({
  dev,
});
const handle = app.getRequestHandler();

Shopify.Context.initialize({
  API_KEY: process.env.SHOPIFY_API_KEY,
  API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
  SCOPES: process.env.SCOPES.split(","),
  HOST_NAME: process.env.HOST.replace(/https:\/\/|\/$/g, ""),
  API_VERSION: ApiVersion.October21,
  IS_EMBEDDED_APP: true,
  // This should be replaced with your preferred storage strategy
  SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});

// Storing the currently active shops in memory will force them to re-login when your server restarts. You should
// persist this object in your app.
const ACTIVE_SHOPIFY_SHOPS = {};

app.prepare().then(async () => {
  const server = new Koa();
  const router = new Router();
  server.keys = [Shopify.Context.API_SECRET_KEY];
  server.use(
    createShopifyAuth({
      async afterAuth(ctx) {
        // Access token and shop available in ctx.state.shopify
        const { shop, accessToken, scope } = ctx.state.shopify;
        const host = ctx.query.host;
        ACTIVE_SHOPIFY_SHOPS[shop] = scope;

        const response = await Shopify.Webhooks.Registry.register({
          shop,
          accessToken,
          path: "/webhooks",
          topic: "APP_UNINSTALLED",
          webhookHandler: async (topic, shop, body) =>
            delete ACTIVE_SHOPIFY_SHOPS[shop],
        });

        if (!response.success) {
          console.log(
            `Failed to register APP_UNINSTALLED webhook: ${response.result}`
          );
        }

        // Redirect to app with shop parameter upon auth
        ctx.redirect(`/?shop=${shop}&host=${host}`);
      },
    })
  );

  const handleRequest = async (ctx) => {
    await handle(ctx.req, ctx.res);
    ctx.respond = false;
    ctx.res.statusCode = 200;
  };

  router.post("/webhooks", async (ctx) => {
    try {
      await Shopify.Webhooks.Registry.process(ctx.req, ctx.res);
      console.log(`Webhook processed, returned status code 200`);
    } catch (error) {
      console.log(`Failed to process webhook: ${error}`);
    }
  });

  router.post(
    "/graphql",
    verifyRequest({ returnHeader: true }),
    async (ctx, next) => {
      await Shopify.Utils.graphqlProxy(ctx.req, ctx.res);
    }
  );

  router.get("(/_next/static/.*)", handleRequest); // Static content is clear
  router.get("/_next/webpack-hmr", handleRequest); // Webpack content is clear
  router.get("(.*)", async (ctx) => {
    const shop = ctx.query.shop;

    // This shop hasn't been seen yet, go through OAuth to create a session
    if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
      ctx.redirect(`/auth?shop=${shop}`);
    } else {
      await handleRequest(ctx);
    }
  });

  server.use(router.allowedMethods());
  server.use(router.routes());
  server.listen(port, () => {
    console.log(`> Ready on http://localhost:${port}`);
  });
});

 

 

Let's solve problems together!
Accepted Solution (1)

g3misa
Shopify Partner
24 5 15

This is an accepted solution.

Ok seems like I solved the issue.  In server.js, instead of using the API_VERSION enum, i used the string value '2021-10' and it worked.  

 

 

Shopify.Context.initialize({
  API_KEY: process.env.SHOPIFY_API_KEY,
  API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
  SCOPES: process.env.SCOPES.split(","),
  HOST_NAME: process.env.HOST.replace(/https:\/\/|\/$/g, ""),
  API_VERSION: '2021-10',   //instead of using the API_VERSION enum, use the string value
  IS_EMBEDDED_APP: true,
  SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});

 

 

Let's solve problems together!

View solution in original post

Replies 2 (2)

g3misa
Shopify Partner
24 5 15

This is an accepted solution.

Ok seems like I solved the issue.  In server.js, instead of using the API_VERSION enum, i used the string value '2021-10' and it worked.  

 

 

Shopify.Context.initialize({
  API_KEY: process.env.SHOPIFY_API_KEY,
  API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
  SCOPES: process.env.SCOPES.split(","),
  HOST_NAME: process.env.HOST.replace(/https:\/\/|\/$/g, ""),
  API_VERSION: '2021-10',   //instead of using the API_VERSION enum, use the string value
  IS_EMBEDDED_APP: true,
  SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});

 

 

Let's solve problems together!
devPrateek
Shopify Partner
4 0 1

This solved my issue, i just upgraded my shopify api version, and this issue suddenly occured, thanks you for the solution