Questions and discussions about using the Shopify CLI and Shopify-built libraries.
Hi all,
So, I'm totally new to developing Shopify Apps and I followed the YouTube tutorial using the Shopify CLI tool (https://www.youtube.com/watch?v=PIXN032XJJ8).
The feature I'm trying to build now is that:
As of now, my index.js where I try to use a fetch looks like this:
import { Page, Form, FormLayout, Checkbox, TextField, Button } from "@shopify/polaris";
import { ResourcePicker } from "@shopify/app-bridge-react";
import React, {useState, useCallback} from "react";
export const Index = () => {
//class Index extends React.Component {
const getCollections = () => {
var fetchUrl = "/api/products";
var method = "GET";
fetch(fetchUrl, { method: method })
.then(response => response.json)
.then(json => console.log(json))
.catch( e => {
console.log(e);
})
}
const [newsletter, setNewsletter] = useState(false);
const [email, setEmail] = useState('');
const handleSubmit = useCallback((_event) => {
console.log('Reminder set for: ', email);
getCollections();
setEmail('');
setNewsletter(false);
}, [email]);
const handleNewsLetterChange = useCallback((value) => {
setNewsletter(value);
},[],
);
const handleEmailChange = useCallback((value) => setEmail(value), []);
return (
<Page
title='You can get reminded about this product'
<Form onSubmit={handleSubmit}>
<FormLayout>
<Checkbox
label="Remind me about this product this weekend"
checked={newsletter}
onChange={handleNewsLetterChange}
/>
<Button submit>Submit</Button>
</FormLayout>
</Form>
</Page>
)
}
export default Index;
And my server.js file looks like this (please have patience with some of the commented code, everything from thing to find a solution before writing this post)
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:\/\//, ""),
API_VERSION: ApiVersion.October20,
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({
accessMode: "offline",
async afterAuth(ctx) {
// Access token and shop available in ctx.state.shopify
const { shop, accessToken, scope } = ctx.state.shopify;
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}`);
},
})
);
const handleRequest = async (ctx) => {
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
};
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);
}
});
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('/api/products', async (ctx) => {
try {
console.log("Inside router executing fetch...");
const results = await fetch("https://" + "storename.myshopify.com" + "/admin/api/2020-10/" + "orders" + ".json", {
headers: {
"Content-Type": "application/json",
"X-Shopify-Access-Token": ctx.state.shopify.accessToken,
},
})
.then(response => response.json())
.then(json => {
console.log("JSON object: ", json)
return json;
});
ctx.body = {
status: 'success',
data: results
};
} catch (err) {
console.log(err)
}
})
router.get("(/_next/static/.*)", handleRequest); // Static content is clear
router.get("/_next/webpack-hmr", handleRequest); // Webpack content is clear
router.get("(.*)", verifyRequest({accessMode: 'offline'}), handleRequest); // Everything else must have sessions (NEW FOR FORUM)
//router.get("(.*)", verifyRequest(), handleRequest); // Everything else must have sessions
server.use(router.allowedMethods());
server.use(router.routes());
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
And here's the log from the console when pushing the butting in the embedded app:
Inside router executing fetch...
┃ JSON object: {
┃ errors: '[API] Invalid API key or access token (unrecognized login or wrong password)'
┃ }
I've been stuck at this stage for days, any help is much appreciated!
Thanks!
Hey !
Did you manage to solve your issue ? I think I'm facing the same problem ://