A space to discuss GraphQL queries, mutations, troubleshooting, throttling, and best practices.
Hi, everyone.
require('isomorphic-fetch');
const dotenv = require('dotenv');
const Koa = require('koa');
const next = require('next');
const { default: createShopifyAuth } = require('@shopify/koa-shopify-auth');
const { verifyRequest } = require('@shopify/koa-shopify-auth');
const session = require('koa-session');
dotenv.config();
const { default: graphQLProxy } = require('@shopify/koa-shopify-graphql-proxy');
const { ApiVersion } = require('@shopify/koa-shopify-graphql-proxy');
const { receiveWebhook, registerWebhook } = require('@shopify/koa-shopify-webhooks');
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const { SHOPIFY_API_SECRET_KEY, SHOPIFY_API_KEY, SHOPIFY_APP_URL } = process.env;
const Router = require('koa-router');
const bodyParser = require('koa-bodyparser');
app.prepare().then(() => {
const server = new Koa();
const router = new Router();
server.use(session({ secure: true, sameSite: 'none' }, server));
server.keys = [SHOPIFY_API_SECRET_KEY];
server.use(
createShopifyAuth({
apiKey: SHOPIFY_API_KEY,
secret: SHOPIFY_API_SECRET_KEY,
scopes: ['write_products', 'write_orders'],
async afterAuth(ctx) {
const { shop, accessToken, scope } = ctx.session;
ctx.cookies.set('shopOrigin', shop, {
httpOnly: false,
secure: true,
sameSite: 'none'
});
const registerProductsUpdate = await registerWebhook({
address: `${SHOPIFY_APP_URL.replace(/https:\/\//, "")}/webhooks/products/update`,
topic: 'PRODUCTS_UPDATE',
accessToken: accessToken,
shop: shop,
ApiVersion: ApiVersion.October20
});
if (registerProductsUpdate.success) {
console.log('Successfully registered webhook PRODUCTS_UPDATE !');
} else {
console.log('Failed to register webhook PRODUCTS_UPDATE ', registerProductsUpdate.result);
}
const registerOrderCreate = await registerWebhook({
address: `${SHOPIFY_APP_URL.replace(/https:\/\//, "")}/webhooks/orders/create`,
topic: 'ORDERS_CREATE',
accessToken: accessToken,
shop: shop,
ApiVersion: ApiVersion.October20
});
if (registerOrderCreate.success) {
console.log('Successfully registered webhook ORDERS_CREATE !');
} else {
console.log('Failed to register webhook ORDERS_CREATE ', registerOrderCreate.result);
}
ctx.redirect(`/?shop=${shop}`);
},
}),
);
const webhook = receiveWebhook({ secret: SHOPIFY_API_SECRET_KEY });
router.post('/webhooks/products/update', webhook, (ctx) => {
try {
console.log(`Webhook processed, returned status code 200`);
} catch (error) {
console.log(`Failed to process webhook: ${error}`);
}
});
router.post('/webhooks/orders/create', webhook, (ctx) => {
try {
console.log(`Webhook processed, returned status code 200`);
} catch (error) {
console.log(`Failed to process webhook: ${error}`);
}
});
server.use(graphQLProxy({ version: ApiVersion.October20 }));
const handleRequest = async (ctx) => {
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
};
router.get("(/_next/static/.*)", handleRequest); // Static content is clear
router.get("/_next/webpack-hmr", handleRequest); // Webpack content is clear
router.get("(.*)", verifyRequest(), handleRequest); // Everything else must have sessions
server
.use(router.allowedMethods())
.use(router.routes());
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
But I got the error
FetchError: invalid json response body at https://*****.myshopify.com/admin/api/undefined/graphql.json reason: Unexpected end of JSON input
I can't register any webhook.
Please help me asap
Solved! Go to the solution
This is an accepted solution.
I've figured it out. For me the issue was when registering webhooks, after updating to @Shopify/koa-shopify-auth package to 4.1.3 from version 3, the "https://" prefix is removed from the HOST environment variable when it was previously included.
Just double check all your options when you register a webhook. Here's what a successful webhook registration looks like for anyone struggling with this issue.
let registerOrdersPaidWebhook = async () => {
// Register Order Paid Webhook
const registerOrdersPaidWebhook = await registerWebhook({
address: `https://${HOST_NAME}/webhooks/orders/paid`,
topic: "ORDERS_PAID",
accessToken,
shop,
apiVersion: ApiVersion.April21,
});
if (registerOrdersPaidWebhook.success) {
console.log("Successfully registered ORDERS_PAID webhook!");
} else {
console.log("Failed to register ORDERS_PAID webhook", registerOrdersPaidWebhook.result);
}
};
Hey @Edith_Jenkins1
It doesn't look like you are defining an API version there. That could possibly be the problem.
Kevin_A | Solutions Engineer @ Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit Shopify.dev or the Shopify Web Design and Development Blog
As you see, I define api version
ApiVersion: ApiVersion.October20
Hey @Edith_Jenkins1
Ah yes I missed that. Can you log the x-request-id response header if possible and send me that?
Kevin_A | Solutions Engineer @ Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit Shopify.dev or the Shopify Web Design and Development Blog
Hey @Kevin_A I'm having this same issue.
A code block that creates an app subscription mutation on install that's been working for months just starting throwing this error after upgrading the @shopify/koa-shopify-auth package to 4.1.3 and moving to session storage. I'm getting the same invalid json error as @Edith_Jenkins1
FetchError: invalid json response body at https://<shop>.myshopify.com/admin/api/undefined/graphql.json reason: Unexpected end of JSON input
I don't know why the URL with "admin/api/UNDEFINED/graphql.json" is being returned in the error. I specify the April 2021 admin api (and I've tried 2020-10, 2021-01 with the same results). Here's the fetch request I'm making:
// This code throws the invalid json error
// Note: query parameter is required to make the mutation
const mutation = JSON.stringify({
query: `mutation {
appSubscriptionCreate(
test: true
name: "name..."
returnUrl: "${returnUrl}"
lineItems: [
{
plan: {
appUsagePricingDetails: {
cappedAmount: { amount: 1500, currencyCode: USD }
terms: "terms..."
}
}
},
{
plan: {
appRecurringPricingDetails: {
price: { amount: 0.00, currencyCode: USD }
}
}
}
]
)
{
userErrors {
field
message
}
confirmationUrl
appSubscription {
id
status
lineItems {
id
plan {
pricingDetails {
__typename
}
}
}
}
}
}`
});
const response = await fetch(
`https://${shop}/admin/api/2021-04/graphql.json`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Shopify-Access-Token": accessToken,
},
body: mutation,
}
);
I can make POST requests to the same url with the same api version, but using a query instead of a mutation and I get back the correct info. For example:
// This code works with no errors
const query = `query {
webhookSubscriptions(first:10) {
edges {
node {
topic
updatedAt
}
}
}
}`;
const response = await fetch(
`https://${shop}/admin/api/2021-04/graphql.json`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Shopify-Access-Token": accessToken,
},
body: JSON.stringify({ query }),
}
);
const responseJson = await response.json();
This query returns the webhook data as expected. I'm not sure what's causing the invalid json error, but I can't install my app to test anything anymore because of it.
Happy to provide any extra info you need to get this solved ASAP.
This is an accepted solution.
I've figured it out. For me the issue was when registering webhooks, after updating to @Shopify/koa-shopify-auth package to 4.1.3 from version 3, the "https://" prefix is removed from the HOST environment variable when it was previously included.
Just double check all your options when you register a webhook. Here's what a successful webhook registration looks like for anyone struggling with this issue.
let registerOrdersPaidWebhook = async () => {
// Register Order Paid Webhook
const registerOrdersPaidWebhook = await registerWebhook({
address: `https://${HOST_NAME}/webhooks/orders/paid`,
topic: "ORDERS_PAID",
accessToken,
shop,
apiVersion: ApiVersion.April21,
});
if (registerOrdersPaidWebhook.success) {
console.log("Successfully registered ORDERS_PAID webhook!");
} else {
console.log("Failed to register ORDERS_PAID webhook", registerOrdersPaidWebhook.result);
}
};