Topics covering webhook creation & management, event handling, Pub/Sub, and Eventbridge, in Shopify apps.
Keeping in mind I'm completely new to creating Shopify apps & React, my goal is to use the /webhooks/orders/create webform to create a new draft order using GraphQL. Here's what I currently have that's successfully firing when a order is created:
router.post('/webhooks/orders/create', webhook, (ctx) => { console.log('received webhook: ', ctx.state.webhook); // Order created, now create draft order });
Question is, what next? Looking at the documentation, looks like I need to use graphql-tag & react-apollo, so tried the following with no luck:
const gql = require('graphql-tag');
const { Mutation } = require('react-apollo');
const createDraftOrder = () => { const CREATE_DRAFT_ORDER = gql` mutation draftOrderCreate($input: DraftOrderInput!) { draftOrderCreate(input: $input) { draftOrder { id } userErrors { field message } } } `; return ( <Mutation mutation={CREATE_DRAFT_ORDER}> {(handleSubmit, { error, data }) => { console.log(error); console.log(data); }} </Mutation> );
}
Seems it doesn't like my return value so probably using this incorrectly. Also know I need to pass the input variables to the mutation, but not sure how. Any help would be greatly appreciated.
Getting closer, think I need to do something along the lines of this after the webhook is fired:
const graphQLEndpoint = 'https://mystore.myshopify.com/admin/api/graphql.json'; return fetch(graphQLEndpoint, { headers: { 'Content-Type': 'application/graphql', 'X-Shopify-Access-Token': 'ACCESS TOKEN', }, body: 'shop { name }', }).then((response) => { console.log(response); return response.json(); });
Now the ?s is how do I get the access token and is the format of body correct in what I'm sending?
I've looked through this: https://help.shopify.com/en/api/getting-started/authentication/oauth
But not sure how to grab it in my server.js. Here's what I've got:
const Koa = require('koa'); const next = require('next'); const { default: createShopifyAuth } = require('@shopify/koa-shopify-auth'); const dotenv = require('dotenv'); const { verifyRequest } = require('@shopify/koa-shopify-auth'); const session = require('koa-session'); require('isomorphic-fetch'); dotenv.config(); const { default: graphQLProxy } = require('@shopify/koa-shopify-graphql-proxy'); const Router = require('koa-router'); 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 routerFunctions = require('./server/router'); const { SHOPIFY_API_SECRET_KEY, SHOPIFY_API_KEY, TUNNEL_URL } = process.env; app.prepare().then(() => { const server = new Koa(); const router = new Router(); server.use(session(server)); server.keys = [SHOPIFY_API_SECRET_KEY]; router.get('/', routerFunctions.processPayment); server.use( createShopifyAuth({ apiKey: SHOPIFY_API_KEY, secret: SHOPIFY_API_SECRET_KEY, scopes: ['read_products', 'write_products', 'write_orders'], async afterAuth(ctx) { const { shop, accessToken } = ctx.session; ctx.cookies.set('shopOrigin', shop, { httpOnly: false }); const registration = await registerWebhook({ address: `${TUNNEL_URL}/webhooks/products/create`, topic: 'PRODUCTS_CREATE', accessToken, shop, }); if (registration.success) { console.log('Successfully registered webhook!'); } else { console.log('Failed to register webhook', registration.result); } // Create order const createOrderWebhook = await registerWebhook({ address: `${TUNNEL_URL}/webhooks/orders/create`, topic: 'ORDERS_CREATE', accessToken, shop, }); if (createOrderWebhook.success) { console.log('Successfully registered createOrderWebhook webhook!'); } else { console.log( 'Failed to register createOrderWebhook webhook', createOrderWebhook.result, ); } // End create order ctx.redirect('/'); }, }), ); const webhook = receiveWebhook({ secret: SHOPIFY_API_SECRET_KEY }); router.post('/webhooks/products/create', webhook, (ctx) => { console.log('received webhook: ', ctx.state.webhook); }); const createDraftOrder = () => { const graphQLEndpoint = 'https://mystore.myshopify.com/admin/api/graphql.json'; return fetch(graphQLEndpoint, { headers: { 'Content-Type': 'application/graphql', 'X-Shopify-Access-Token': '', }, body: 'shop { name }', }).then((response) => { console.log(response); return response.json(); }); }; router.post('/webhooks/orders/create', webhook, (ctx) => { // NEED TO MAKE THE CREATE NEW DRAFT ORDER VIA GRAPHQL HERE createDraftOrder(); }); // End order created server.use(graphQLProxy()); router.get('*', verifyRequest(), async (ctx) => { await handle(ctx.req, ctx.res); ctx.respond = false; ctx.res.statusCode = 200; return; }); server.use(router.allowedMethods()); server.use(router.routes()); server.listen(port, () => { console.log(`> Ready on http://localhost:${port}`); }); });
Was this ever resolved? I'm having exactly the same issue here.
Same here, did anyone solved it?
Also, can anyone explain how in the tutorial there was a part of the server js code that read
server.use(verifyRequest()); server.use(async (ctx) => { await handle(ctx.req, ctx.res); ctx.respond = false; ctx.res.statusCode = 200; return });
But in the example above it was changed into:
router.get('*', verifyRequest(), async (ctx) => { await handle(ctx.req, ctx.res); ctx.respond = false; ctx.res.statusCode = 200; return; });
How do you know when you have to handle this part of the server routines(first code snippet above) in another class (seconde code snippet above)