Skip to content

Commit 28e4374

Browse files
committed
fix: rename catalog functions
1 parent f1c2d27 commit 28e4374

File tree

7 files changed

+145
-128
lines changed

7 files changed

+145
-128
lines changed

src/catalog/fetch.js

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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+
/* eslint-disable no-await-in-loop */
14+
15+
import { errorResponse } from '../utils/http.js';
16+
import { fetchProduct } from '../utils/r2.js';
17+
18+
/**
19+
* Handles a GET request for a product.
20+
* @param {Context} ctx - The context object containing request information and utilities.
21+
* @param {Config} config - The configuration object with application settings.
22+
* @returns {Promise<Response>} - A promise that resolves to the product response.
23+
*/
24+
export async function handleProductFetchRequest(ctx, config) {
25+
try {
26+
const sku = ctx.url.pathname.split('/').pop();
27+
const product = await fetchProduct(ctx, config, sku);
28+
29+
return new Response(JSON.stringify(product), {
30+
headers: { 'Content-Type': 'application/json' },
31+
});
32+
} catch (e) {
33+
if (e.response) {
34+
return e.response;
35+
}
36+
ctx.log.error(e);
37+
return errorResponse(500, 'internal server error');
38+
}
39+
}

src/catalog/handler.js

+14-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313
import { errorResponse } from '../utils/http.js';
1414
import { handleProductLookupRequest } from './lookup.js';
15-
import { handleProductGetRequest, handleProductPutRequest } from './product.js';
15+
import { handleProductFetchRequest } from './fetch.js';
16+
import { handleProductSaveRequest } from './update.js';
1617

1718
const ALLOWED_METHODS = ['GET', 'PUT'];
1819

@@ -24,15 +25,22 @@ const ALLOWED_METHODS = ['GET', 'PUT'];
2425
* @returns {Promise<Response>} - A promise that resolves to the catalog response.
2526
*/
2627
export default async function catalogHandler(ctx, config, request) {
27-
if (!ALLOWED_METHODS.includes(ctx.info.method)) {
28+
const { method } = ctx.info;
29+
30+
// Split the pathname into segments and filter out empty strings
31+
const pathSegments = ctx.url.pathname.split('/').filter(Boolean);
32+
33+
if (!ALLOWED_METHODS.includes(method)) {
2834
return errorResponse(405, 'method not allowed');
2935
}
3036

31-
const pathSegments = ctx.url.pathname.split('/');
3237
const catalogIndex = pathSegments.indexOf('catalog');
38+
if (catalogIndex === -1) {
39+
return errorResponse(400, 'Invalid URL: Missing "catalog" segment');
40+
}
3341

3442
if (catalogIndex === -1 || pathSegments.length < catalogIndex + 5) {
35-
throw new Error('Invalid URL structure: Expected format: /catalog/{env}/{store}/{storeView}/{product}[/{sku}]');
43+
return errorResponse(400, 'Invalid URL structure: Expected format: /catalog/{env}/{store}/{storeView}/product/{sku}');
3644
}
3745

3846
const [env, storeCode, storeViewCode, subRoute, sku] = pathSegments.slice(catalogIndex + 1);
@@ -49,7 +57,7 @@ export default async function catalogHandler(ctx, config, request) {
4957
}
5058

5159
if (ctx.info.method === 'PUT') {
52-
return handleProductPutRequest(ctx, config, request);
60+
return handleProductSaveRequest(ctx, config, request);
5361
}
54-
return handleProductGetRequest(ctx, config);
62+
return handleProductFetchRequest(ctx, config);
5563
}

src/catalog/lookup.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*/
1212

1313
import { errorResponse } from '../utils/http.js';
14-
import { listAllProducts, loadProductFromR2, resolveSku } from '../utils/r2.js';
14+
import { listAllProducts, fetchProduct, lookupSku } from '../utils/r2.js';
1515

1616
/**
1717
* Handles a product lookup request.
@@ -21,11 +21,12 @@ import { listAllProducts, loadProductFromR2, resolveSku } from '../utils/r2.js';
2121
*/
2222
export async function handleProductLookupRequest(ctx, config) {
2323
try {
24-
const params = new URLSearchParams(ctx.url.search);
24+
const { search } = ctx.url;
25+
const params = new URLSearchParams(search);
2526

2627
if (params.has('urlKey')) {
27-
const sku = await resolveSku(ctx, config, params.get('urlKey'));
28-
const product = await loadProductFromR2(ctx, config, sku);
28+
const sku = await lookupSku(ctx, config, params.get('urlKey'));
29+
const product = await fetchProduct(ctx, config, sku);
2930
return new Response(JSON.stringify(product), {
3031
headers: { 'Content-Type': 'application/json' },
3132
});

src/catalog/product.js

-111
This file was deleted.

src/catalog/update.js

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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+
/* eslint-disable no-await-in-loop */
14+
15+
import { callAdmin } from '../utils/admin.js';
16+
import { errorResponse, errorWithResponse } from '../utils/http.js';
17+
import { saveProducts } from '../utils/r2.js';
18+
19+
/**
20+
* Saves a product to R2.
21+
* @param {Context} ctx - The context object containing request information and utilities.
22+
* @param {Config} config - The configuration object with application settings.
23+
* @param {Object} product - The product object to be saved.
24+
* @returns {Promise<Object>} - A promise that resolves to the saved product.
25+
*/
26+
async function putProduct(ctx, config, product) {
27+
if (!product.sku) {
28+
throw errorWithResponse(400, 'invalid request body: missing sku');
29+
}
30+
31+
await saveProducts(ctx, config, [product]);
32+
return product;
33+
}
34+
35+
/**
36+
* Handles a PUT request to update a product.
37+
* @param {Context} ctx - The context object containing request information and utilities.
38+
* @param {Config} config - The configuration object with application settings.
39+
* @param {Request} request - The request object.
40+
* @returns {Promise<Response>} - A promise that resolves to the product response.
41+
*/
42+
export async function handleProductSaveRequest(ctx, config, request) {
43+
try {
44+
const requestBody = await request.json();
45+
46+
if (config.sku === '*') {
47+
return errorResponse(501, 'not implemented');
48+
}
49+
50+
const product = await putProduct(ctx, config, requestBody);
51+
const products = [product];
52+
53+
const matchedKeys = Object.keys(config.confMap)
54+
.filter((key) => config.confMap[key].env === config.env);
55+
56+
for (const purgeProduct of products) {
57+
for (const key of matchedKeys) {
58+
let path = key.replace('{{sku}}', purgeProduct.sku);
59+
60+
if (key.includes('{{urlkey}}') && purgeProduct.urlKey) {
61+
path = path.replace('{{urlkey}}', purgeProduct.urlKey);
62+
}
63+
64+
for (const env of ['preview', 'live']) {
65+
const response = await callAdmin(config, env, path, { method: 'post' });
66+
if (!response.ok) {
67+
return errorResponse(400, `failed to ${env} product`);
68+
}
69+
}
70+
}
71+
}
72+
return new Response(undefined, { status: 201 });
73+
} catch (e) {
74+
if (e.response) {
75+
return e.response;
76+
}
77+
ctx.log.error(e);
78+
return errorResponse(500, 'internal server error');
79+
}
80+
}

src/content/helix-commerce.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*/
1212

1313
import { errorResponse } from '../utils/http.js';
14-
import { loadProductFromR2 } from '../utils/r2.js';
14+
import { fetchProduct } from '../utils/r2.js';
1515
import HTML_TEMPLATE from '../templates/html.js';
1616

1717
export async function handle(ctx, config) {
@@ -23,7 +23,7 @@ export async function handle(ctx, config) {
2323
}
2424

2525
config.env = 'prod';
26-
const product = await loadProductFromR2(ctx, config, sku);
26+
const product = await fetchProduct(ctx, config, sku);
2727
const html = HTML_TEMPLATE(product, product.variants);
2828
return new Response(html, {
2929
status: 200,

src/utils/r2.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ import { errorWithResponse } from './http.js';
1515
/* eslint-disable no-await-in-loop */
1616

1717
/**
18-
* Load product from R2 using SKU
18+
* Load product by SKU
1919
* @param {Context} ctx - The context object.
2020
* @param {Config} config - The config object.
2121
* @param {string} sku - The SKU of the product.
2222
* @returns {Promise<Product>} - A promise that resolves to the product.
2323
*/
24-
export async function loadProductFromR2(ctx, config, sku) {
24+
export async function fetchProduct(ctx, config, sku) {
2525
const key = `${config.org}/${config.site}/${config.env}/${config.storeCode}/${config.storeViewCode}/${sku}.json`;
2626
const object = await ctx.env.CATALOG_BUCKET.get(key);
2727

@@ -38,13 +38,13 @@ export async function loadProductFromR2(ctx, config, sku) {
3838
}
3939

4040
/**
41-
* Save products to R2
41+
* Save products
4242
* @param {Context} ctx - The context object.
4343
* @param {Config} config - The config object.
4444
* @param {Product[]} products - The products to save.
4545
* @returns {Promise<void>} - A promise that resolves when the products are saved.
4646
*/
47-
export async function saveProductsToR2(ctx, config, products) {
47+
export async function saveProducts(ctx, config, products) {
4848
const { log } = ctx;
4949
const BATCH_SIZE = 50;
5050

@@ -93,7 +93,7 @@ export async function saveProductsToR2(ctx, config, products) {
9393
* @param {string} urlKey - The URL key.
9494
* @returns {Promise<string>} - A promise that resolves to the SKU.
9595
*/
96-
export async function resolveSku(ctx, config, urlKey) {
96+
export async function lookupSku(ctx, config, urlKey) {
9797
// Make a HEAD request to retrieve the SKU from metadata based on the URL key
9898
const urlKeyPath = `${config.org}/${config.site}/${config.env}/${config.storeCode}/${config.storeViewCode}/urlkeys/${urlKey}`;
9999
const headResponse = await ctx.env.CATALOG_BUCKET.head(urlKeyPath);

0 commit comments

Comments
 (0)