我在编码和shopify方面完全是新手,我知道如何在普通的JS中获取API,但我不太清楚它在node.js中是如何工作的和如何反应的。我一直在尽我最大的努力去阅读这些文档,但是所有的东西看起来都很模糊。而在线教程似乎不一样或过时了。我确实成功地通过了Shopify CLI。基本上,我想阅读产品名称,并通过应用程序更新它们。
到目前为止,我想首先做的是console.log产品名称,但我似乎做不到。我能够访问返回api的https://[name].myshopify.com/admin/api/2022-10/products.json,但是我不能将它放在我的前端。到目前为止,我得到了一个get https://7172-60--**.jp.ngrok.io/undefined/admin/api/2022-10/products.json 404与我的代码。我试图用我的代码做的是,当单击表单按钮时,API将被记录下来。
这是我的密码。
后端代码web/index.js
import { join } from "path";
import { readFileSync } from "fs";
import express from "express";
import cookieParser from "cookie-parser";
import { Shopify, LATEST_API_VERSION } from "@shopify/shopify-api";
import applyAuthMiddleware from "./middleware/auth.js";
import verifyRequest from "./middleware/verify-request.js";
import { setupGDPRWebHooks } from "./gdpr.js";
import productCreator from "./helpers/product-creator.js";
import redirectToAuth from "./helpers/redirect-to-auth.js";
import { BillingInterval } from "./helpers/ensure-billing.js";
import { AppInstallations } from "./app_installations.js";
import {Product} from '@shopify/shopify-api/dist/rest-resources/2022-10/index.js';
import cors from 'cors';
const USE_ONLINE_TOKENS = false;
const PORT = parseInt(process.env.BACKEND_PORT || process.env.PORT, 10);
// TODO: There should be provided by env vars
const DEV_INDEX_PATH = `${process.cwd()}/frontend/`;
const PROD_INDEX_PATH = `${process.cwd()}/frontend/dist/`;
const DB_PATH = `${process.cwd()}/database.sqlite`;
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?:\/\//, ""),
HOST_SCHEME: process.env.HOST.split("://")[0],
API_VERSION: LATEST_API_VERSION,
IS_EMBEDDED_APP: true,
// This should be replaced with your preferred storage strategy
// See note below regarding using CustomSessionStorage with this template.
SESSION_STORAGE: new Shopify.Session.SQLiteSessionStorage(DB_PATH),
...(process.env.SHOP_CUSTOM_DOMAIN && {CUSTOM_SHOP_DOMAINS: [process.env.SHOP_CUSTOM_DOMAIN]}),
});
// NOTE: If you choose to implement your own storage strategy using
// Shopify.Session.CustomSessionStorage, you MUST implement the optional
// findSessionsByShopCallback and deleteSessionsCallback methods. These are
// required for the app_installations.js component in this template to
// work properly.
Shopify.Webhooks.Registry.addHandler("APP_UNINSTALLED", {
path: "/api/webhooks",
webhookHandler: async (_topic, shop, _body) => {
await AppInstallations.delete(shop);
},
});
// The transactions with Shopify will always be marked as test transactions, unless NODE_ENV is production.
// See the ensureBilling helper to learn more about billing in this template.
const BILLING_SETTINGS = {
required: false,
// This is an example configuration that would do a one-time charge for $5 (only USD is currently supported)
// chargeName: "My Shopify One-Time Charge",
// amount: 5.0,
// currencyCode: "USD",
// interval: BillingInterval.OneTime,
};
// This sets up the mandatory GDPR webhooks. You’ll need to fill in the endpoint
// in the “GDPR mandatory webhooks” section in the “App setup” tab, and customize
// the code when you store customer data.
//
// More details can be found on shopify.dev:
// https://shopify.dev/apps/webhooks/configuration/mandatory-webhooks
setupGDPRWebHooks("/api/webhooks");
// export for test use only
export async function createServer(
root = process.cwd(),
isProd = process.env.NODE_ENV === "production",
billingSettings = BILLING_SETTINGS
) {
const app = express();
app.set("use-online-tokens", USE_ONLINE_TOKENS);
app.use(cookieParser(Shopify.Context.API_SECRET_KEY));
applyAuthMiddleware(app, {
billing: billingSettings,
});
// Do not call app.use(express.json()) before processing webhooks with
// Shopify.Webhooks.Registry.process().
// See https://github.com/Shopify/shopify-api-node/blob/main/docs/usage/webhooks.md#note-regarding-use-of-body-parsers
// for more details.
app.post("/api/webhooks", async (req, res) => {
try {
await Shopify.Webhooks.Registry.process(req, res);
console.log(`Webhook processed, returned status code 200`);
} catch (e) {
console.log(`Failed to process webhook: ${e.message}`);
if (!res.headersSent) {
res.status(500).send(e.message);
}
}
});
// All endpoints after this point will require an active session
app.use(
"/api/*",
verifyRequest(app, {
billing: billingSettings,
})
);
app.get('/admin/api/2022-10/products.json', async (request, response) => {
const test_session = await Shopify.Utils.loadCurrentSession(request, response);
const app = express();
app.use(cors());
await Product.all({
session: test_session,
});
});
app.get("/api/products/count", async (req, res) => {
const session = await Shopify.Utils.loadCurrentSession(
req,
res,
app.get("use-online-tokens")
);
const { Product } = await import(
`@shopify/shopify-api/dist/rest-resources/${Shopify.Context.API_VERSION}/index.js`
);
const countData = await Product.count({ session });
res.status(200).send(countData);
});
app.get("/api/products/create", async (req, res) => {
const session = await Shopify.Utils.loadCurrentSession(
req,
res,
app.get("use-online-tokens")
);
let status = 200;
let error = null;
try {
await productCreator(session);
} catch (e) {
console.log(`Failed to process products/create: ${e.message}`);
status = 500;
error = e.message;
}
res.status(status).send({ success: status === 200, error });
});
// All endpoints after this point will have access to a request.body
// attribute, as a result of the express.json() middleware
app.use(express.json());
app.use((req, res, next) => {
const shop = Shopify.Utils.sanitizeShop(req.query.shop);
if (Shopify.Context.IS_EMBEDDED_APP && shop) {
res.setHeader(
"Content-Security-Policy",
`frame-ancestors https://${encodeURIComponent(
shop
)} https://admin.shopify.com;`
);
} else {
res.setHeader("Content-Security-Policy", `frame-ancestors 'none';`);
}
next();
});
if (isProd) {
const compression = await import("compression").then(
({ default: fn }) => fn
);
const serveStatic = await import("serve-static").then(
({ default: fn }) => fn
);
app.use(compression());
app.use(serveStatic(PROD_INDEX_PATH, { index: false }));
}
app.use("/*", async (req, res, next) => {
if (typeof req.query.shop !== "string") {
res.status(500);
return res.send("No shop provided");
}
const shop = Shopify.Utils.sanitizeShop(req.query.shop);
const appInstalled = await AppInstallations.includes(shop);
if (!appInstalled && !req.originalUrl.match(/^\/exitiframe/i)) {
return redirectToAuth(req, res, app);
}
if (Shopify.Context.IS_EMBEDDED_APP && req.query.embedded !== "1") {
const embeddedUrl = Shopify.Utils.getEmbeddedAppUrl(req);
return res.redirect(embeddedUrl + req.path);
}
const htmlFile = join(
isProd ? PROD_INDEX_PATH : DEV_INDEX_PATH,
"index.html"
);
return res
.status(200)
.set("Content-Type", "text/html")
.send(readFileSync(htmlFile));
}
);
return { app };
}
createServer().then(({ app }) => app.listen(PORT));这是我的前端/web/page/index.js
import { React, useState, useCallback } from "react";
import {
Page,
Layout,
Card,
Button,
Form,
FormLayout,
TextField,
Stack,
} from "@shopify/polaris";
import { ResourcePicker } from "@shopify/app-bridge-react";
import axios from "axios";
const axiosGetData = () => {
axios({
url: `${process.env.SHOP}/admin/api/2022-10/products.json`,
method: "GET",
headers: {
'X-Shopify-Access-Token': `${process.env.TOKEN}`,
'Content-Type': 'application/json'
},
})
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
};
const index = () => {
const [value, setValue] = useState("Name");
const [state, setState] = useState(false);
const handleChange = useCallback((newValue) => setValue(newValue), []);
function handleSubmit(e) {
setState(true);
e.preventDefault();
console.log(value);
axiosGetData();
}
function handleCancel() {
setState(false);
}
function handleSelection(resources) {
setState(false);
resources.selection.map((name) => (name.handle = value));
console.log(resources.selection);
}
return (
<Page title="My Shop">
<Layout>
<Layout.Section>
<Card title="Change Product Name" sectioned>
<Form onSubmit={handleSubmit}>
<FormLayout>
<TextField
label="Type on the input the new name and select which product name to change"
value={value}
onChange={handleChange}
/>
<Button primary submit>
Select Product
</Button>
</FormLayout>
<ResourcePicker
resourceType="Product"
open={state}
onCancel={handleCancel}
onSelection={handleSelection}
/>
</Form>
</Card>
</Layout.Section>
</Layout>
</Page>
);
};
export default index;发布于 2022-11-01 16:38:58
最大的问题是你在FE上得到的URL是不正确的。您的服务器在localhost/ngrok上运行,因此要访问它,您应该在URL中取出${process.env.SHOP}。所以路线应该是-> /admin/api/2022-10/products.json。
您可以看到这方面的一个示例,通过查看Shopify提供的示例应用程序构建(https://shopify.dev/apps/getting-started/build-app-example),可以更好地了解它是如何工作的。
重要的是要注意,这些不是Shopify特定的概念,所以您应该浏览一下Express应用程序的路由,以及如何从你的FE到达端点。Shopify在它们的模板中抽象了很多东西,很容易混淆事情发生在哪里,所以花时间阅读代码,看看正在发生的事情会非常有帮助
https://stackoverflow.com/questions/74275982
复制相似问题