Skip to content

Commit 61196f1

Browse files
committed
fix: moving to core query
1 parent e5db728 commit 61196f1

File tree

7 files changed

+476
-242
lines changed

7 files changed

+476
-242
lines changed

src/index.js

+52-241
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@
99
* OF ANY KIND, either express or implied. See the License for the specific language
1010
* governing permissions and limitations under the License.
1111
*/
12-
1312
// @ts-check
1413

14+
import { errorResponse, makeContext } from './util.js';
15+
import getProductQueryCS from './queries/cs-product.js';
16+
import getProductQueryCore from './queries/core-product.js';
17+
import HTML_TEMPLATE from './templates/html.js';
18+
1519
/**
1620
* @type {Record<string, Config>}
1721
*/
@@ -21,54 +25,10 @@ const TENANT_CONFIGS = {
2125
magentoEnvironmentId: '97034e45-43a5-48ab-91ab-c9b5a98623a8',
2226
magentoWebsiteCode: 'base',
2327
magentoStoreViewCode: 'default',
28+
coreEndpoint: 'https://www.visualcomfort.com/graphql',
2429
},
2530
};
2631

27-
/**
28-
* @param {TemplateStringsArray} strs
29-
* @param {...any} params
30-
* @returns {string}
31-
*/
32-
export function gql(strs, ...params) {
33-
let res = '';
34-
strs.forEach((s, i) => {
35-
res += s;
36-
if (i < params.length) {
37-
res += params[i];
38-
}
39-
});
40-
return res.replace(/(\\r\\n|\\n|\\r)/gm, ' ').replace(/\s+/g, ' ').trim();
41-
}
42-
43-
/**
44-
* @param {number} status
45-
* @param {string} xError
46-
* @param {string|Record<string,unknown>} [body='']
47-
* @returns
48-
*/
49-
function errorResponse(status, xError, body = '') {
50-
return new Response(typeof body === 'object' ? JSON.stringify(body) : body, {
51-
status,
52-
headers: { 'x-error': xError },
53-
});
54-
}
55-
56-
/**
57-
* @param {import("@cloudflare/workers-types/experimental").ExecutionContext} pctx
58-
* @param {Request} req
59-
* @param {Record<string, string>} env
60-
* @returns {Context}
61-
*/
62-
function makeContext(pctx, req, env) {
63-
/** @type {Context} */
64-
// @ts-ignore
65-
const ctx = pctx;
66-
ctx.env = env;
67-
ctx.url = new URL(req.url);
68-
ctx.log = console;
69-
return ctx;
70-
}
71-
7232
/**
7333
* @param {string} tenant
7434
* @param {Partial<Config>} [overrides={}]
@@ -89,140 +49,50 @@ function lookupConfig(tenant, overrides) {
8949
* @param {string} sku
9050
* @param {Config} config
9151
*/
92-
async function fetchProduct(sku, config) {
93-
const query = gql`{
94-
products(
95-
skus: ["${sku}"]
96-
) {
97-
__typename
98-
id
99-
sku
100-
name
101-
metaTitle
102-
metaDescription
103-
metaKeyword
104-
description
105-
url
106-
urlKey
107-
shortDescription
108-
url
109-
addToCartAllowed
110-
inStock
111-
images(roles: []) {
112-
url
113-
label
114-
roles
115-
__typename
116-
}
117-
attributes(roles: []) {
118-
name
119-
label
120-
value
121-
roles
122-
__typename
123-
}
124-
... on SimpleProductView {
125-
price {
126-
final {
127-
amount {
128-
value
129-
currency
130-
__typename
131-
}
132-
__typename
133-
}
134-
regular {
135-
amount {
136-
value
137-
currency
138-
__typename
139-
}
140-
__typename
141-
}
142-
roles
143-
__typename
144-
}
145-
__typename
146-
}
147-
... on ComplexProductView {
148-
options {
149-
id
150-
title
151-
required
152-
values {
153-
id
154-
title
155-
... on ProductViewOptionValueProduct {
156-
product {
157-
sku
158-
name
159-
__typename
160-
}
161-
__typename
162-
}
163-
... on ProductViewOptionValueSwatch {
164-
type
165-
value
166-
__typename
167-
}
168-
__typename
169-
}
170-
__typename
171-
}
172-
priceRange {
173-
maximum {
174-
final {
175-
amount {
176-
value
177-
currency
178-
__typename
179-
}
180-
__typename
181-
}
182-
regular {
183-
amount {
184-
value
185-
currency
186-
__typename
187-
}
188-
__typename
189-
}
190-
roles
191-
__typename
192-
}
193-
minimum {
194-
final {
195-
amount {
196-
value
197-
currency
198-
__typename
199-
}
200-
__typename
201-
}
202-
regular {
203-
amount {
204-
value
205-
currency
206-
__typename
207-
}
208-
__typename
209-
}
210-
roles
211-
__typename
212-
}
213-
__typename
214-
}
215-
__typename
216-
}
217-
}
218-
}`;
52+
async function fetchProductCS(sku, config) {
53+
const query = getProductQueryCS({ sku });
21954

22055
const resp = await fetch(`https://catalog-service.adobe.io/graphql?query=${encodeURIComponent(query)}`, {
221-
// method: 'POST',
222-
// body: query,
22356
headers: {
224-
origin: 'https://adobecommerce.live',
225-
// 'content-type':'application/json',
57+
origin: 'https://api.adobecommerce.live',
58+
'x-api-key': config.apiKey,
59+
'Magento-Environment-Id': config.magentoEnvironmentId,
60+
'Magento-Website-Code': config.magentoWebsiteCode,
61+
'Magento-Store-View-Code': config.magentoStoreViewCode,
62+
},
63+
});
64+
if (!resp.ok) {
65+
console.warn('failed to fetch product: ', resp.status);
66+
return resp;
67+
}
68+
69+
const json = await resp.json();
70+
try {
71+
const [product] = json.data.products;
72+
if (!product) {
73+
return errorResponse(404, 'could not find product', json.errors);
74+
}
75+
return product;
76+
} catch (e) {
77+
console.error('failed to parse product: ', e);
78+
return errorResponse(500, 'failed to parse product response');
79+
}
80+
}
81+
82+
/**
83+
* @param {{ urlKey: string } | { sku: string }} opt
84+
* @param {Config} config
85+
*/
86+
// eslint-disable-next-line no-unused-vars
87+
async function fetchProductCore(opt, config) {
88+
const query = getProductQueryCore(opt);
89+
if (!config.coreEndpoint) {
90+
return errorResponse(400, 'coreEndpoint not configured');
91+
}
92+
93+
const resp = await fetch(`${config.coreEndpoint}?query=${encodeURIComponent(query)}`, {
94+
headers: {
95+
origin: 'https://api.adobecommerce.live',
22696
'x-api-key': config.apiKey,
22797
'Magento-Environment-Id': config.magentoEnvironmentId,
22898
'Magento-Website-Code': config.magentoWebsiteCode,
@@ -248,68 +118,7 @@ async function fetchProduct(sku, config) {
248118
}
249119

250120
function resolvePDPTemplate(product) {
251-
return /* html */`
252-
<!DOCTYPE html>
253-
<html>
254-
<head>
255-
<title>${product.metaTitle || product.name}</title>
256-
<meta property="description" content="${product.metaDescription || product.description}">
257-
<meta property="og:title" content="${product.metaTitle || product.name}">
258-
<meta property="og:image" content="${product.images[0].url}">
259-
<meta property="og:image:secure_url" content="${product.images[0].url}">
260-
<meta name="twitter:card" content="summary_large_image">
261-
<meta name="twitter:title" content="${product.metaTitle || product.name}">
262-
<meta name="twitter:image" content="${product.images[0].url}">
263-
<meta name="viewport" content="width=device-width, initial-scale=1">
264-
<script src="/scripts/aem.js" type="module"></script>
265-
<script src="/scripts/scripts.js" type="module"></script>
266-
<link rel="stylesheet" href="/styles/styles.css">
267-
</head>
268-
<body>
269-
<header></header>
270-
<main>
271-
<div>
272-
<h1>${product.name}</h1>
273-
<div class="product-gallery">
274-
<div>
275-
${product.images.map((img) => `
276-
<div>
277-
<picture>
278-
<source type="image/webp" srcset="${img.url}" alt="" media="(min-width: 600px)">
279-
<source type="image/webp" srcset="${img.url}">
280-
<source type="image/png" srcset="${img.url}" media="(min-width: 600px)">
281-
<img loading="lazy" alt="${img.label}" src="${img.url}">
282-
</picture>
283-
</div>`).join('\n')}
284-
</div>
285-
</div>
286-
<div class="product-attributes">
287-
${product.attributes.map((attr) => `
288-
<div>
289-
<div>${attr.name}</div>
290-
<div>${attr.label}</div>
291-
<div>${attr.value}</div>
292-
</div>`).join('\n')}
293-
</div>
294-
<div class="product-options">
295-
${product.options.map((opt) => `
296-
<div>
297-
<div>${opt.id}</div>
298-
<div>${opt.title}</div>
299-
<div>${opt.required === true ? 'required' : ''}</div>
300-
</div>
301-
${opt.values.map((val) => `
302-
<div>
303-
<div>${val.id}</div>
304-
<div>${val.title}</div>
305-
</div>`).join('\n')}`).join('\n')}
306-
</div>
307-
</div>
308-
</main>
309-
<footer></footer>
310-
</body>
311-
</html>
312-
`;
121+
return HTML_TEMPLATE(product);
313122
}
314123

315124
/**
@@ -322,12 +131,14 @@ async function handlePDPRequest(ctx) {
322131
return errorResponse(404, 'missing sku');
323132
}
324133

325-
const config = lookupConfig(tenant, {}); // TODO: allow config overrides from query params
134+
const overrides = Object.fromEntries(ctx.url.searchParams.entries());
135+
const config = lookupConfig(tenant, overrides);
326136
if (!config) {
327137
return errorResponse(404, 'config not found');
328138
}
329139

330-
const product = await fetchProduct(sku, config);
140+
// const product = await fetchProductCore({ sku }, config);
141+
const product = await fetchProductCS(sku, config);
331142
const html = resolvePDPTemplate(product);
332143
return new Response(html, {
333144
status: 200,

src/queries/core-product.js

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2024 Adobe. All rights reserved.
3+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License. You may obtain a copy
5+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under
8+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
* OF ANY KIND, either express or implied. See the License for the specific language
10+
* governing permissions and limitations under the License.
11+
*/
12+
13+
import { gql } from '../util.js';
14+
15+
/**
16+
* @param {{ urlKey?: string; sku?: string; }} param0
17+
*/
18+
export default ({ urlKey, sku }) => gql`{
19+
products(
20+
filter: { ${urlKey ? 'url_key' : 'sku'}: { eq: "${urlKey ?? sku}" } }
21+
) {
22+
items {
23+
sku
24+
name
25+
meta_title
26+
meta_keyword
27+
meta_description
28+
short_description {
29+
html
30+
}
31+
description {
32+
html
33+
}
34+
image {
35+
url
36+
label
37+
disabled
38+
}
39+
thumbnail {
40+
url
41+
label
42+
}
43+
media_gallery {
44+
url
45+
label
46+
}
47+
categories {
48+
category_seo_name
49+
breadcrumbs {
50+
category_name
51+
category_level
52+
}
53+
}
54+
}
55+
}
56+
}`;

0 commit comments

Comments
 (0)