app.post(‘/api/create-active-product’, async (req, res) => {
const {
productName,
frontImage,
backImage,
shop,
designName,
description,
sellingPrice,
SKUs,
status,
userId
} = req.body;
try {
// Get the access token for the shop
const accessToken = await getAccessToken(userId);
// Step 1: Create the product without media, options, and variants
const createProductMutation = {
query: `mutation createProduct($input: ProductInput!) {
productCreate(input: $input) {
product {
id
title
descriptionHtml
status
}
userErrors {
field
message
}
}
}`,
variables: {
input: {
title: designName,
descriptionHtml: description,
status: status.toLowerCase() === "active" ? "ACTIVE" : "DRAFT",
},
},
};
// Log the data being sent to Shopify for debugging
console.log('Sending Product Data to Shopify:', JSON.stringify(createProductMutation, null, 2));
// Send the request to Shopify's GraphQL API
const productResponse = await axios.post(
`https://${shop}/admin/api/2024-07/graphql.json`, // Correct API version
createProductMutation,
{
headers: {
'X-Shopify-Access-Token': accessToken,
'Content-Type': 'application/json',
},
}
);
if (productResponse.data.errors) {
console.log('GraphQL Errors:', JSON.stringify(productResponse.data.errors, null, 2));
return res.status(400).json({ error: 'GraphQL errors', details: productResponse.data.errors });
}
const productId = productResponse.data.data.productCreate.product.id;
console.log(`Product created with ID: ${productId}`);
// Step 2: Create Media (Images or Video) - Mutation for Media (Images)
const createMediaMutation = {
query: `mutation productCreateMedia($media: [CreateMediaInput!]!, $productId: ID!) {
productCreateMedia(media: $media, productId: $productId) {
media {
alt
mediaContentType
status
}
mediaUserErrors {
field
message
}
}
}`,
variables: {
media: [
{ alt: `${productName} Front Design`, mediaContentType: "IMAGE", originalSource: frontImage },
{ alt: `${productName} Back Design`, mediaContentType: "IMAGE", originalSource: backImage }
],
productId: productId,
},
};
const mediaResponse = await axios.post(
`https://${shop}/admin/api/2024-07/graphql.json`,
createMediaMutation,
{
headers: {
'X-Shopify-Access-Token': accessToken,
'Content-Type': 'application/json',
},
}
);
if (mediaResponse.data.errors) {
console.log('GraphQL Errors in media mutation:', JSON.stringify(mediaResponse.data.errors, null, 2));
return res.status(400).json({ error: 'GraphQL errors in media mutation', details: mediaResponse.data.errors });
}
console.log('Media added successfully.');
const uniqueSizes = [...new Set(SKUs.map(sku => sku.split('-').pop()))];
// Step 3: Create Product Options (e.g., Size)
const createOptionsMutation = {
query: `mutation createOptions($productId: ID!, $options: [OptionCreateInput!]!) {
productOptionsCreate(productId: $productId, options: $options) {
userErrors {
field
message
}
product {
options {
name
linkedMetafield {
namespace
key
}
optionValues {
name
linkedMetafieldValue
}
}
}
}
}`,
variables: {
productId: productId,
options: [
{
name: "Size", // Creating a "Size" option
values: uniqueSizes.map(size => ({ name: size })),
}
],
},
};
const optionsResponse = await axios.post(
`https://${shop}/admin/api/2024-07/graphql.json`,
createOptionsMutation,
{
headers: {
'X-Shopify-Access-Token': accessToken,
'Content-Type': 'application/json',
},
}
);
if (optionsResponse.data.errors) {
console.log('GraphQL Errors in options mutation:', JSON.stringify(optionsResponse.data.errors, null, 2));
return res.status(400).json({ error: 'GraphQL errors in options mutation', details: optionsResponse.data.errors });
}
console.log('Options added successfully.');
// Step 4: Dynamically Fetch the Option ID for "Size"
const sizeOption = optionsResponse.data.data.productOptionsCreate.product.options.find(option => option.name === "Size");
if (!sizeOption) {
console.error("Size option not found.");
return res.status(400).json({ error: "Size option not found." });
}
const sizeOptionId = sizeOption.id; // Dynamically found optionId for "Size"
// Step 5: Create Product Variants
const variants = SKUs.map((sku, index) => {
const size = sku.split('-').pop(); // Mapping size to SKU
return {
price: sellingPrice,
inventoryItem: {
sku: sku,
tracked: true,
// Pass the SKU as a key-value object
},
// sku: sku, // SKU correctly inside the variant
inventoryQuantities: [
{
locationId: 'gid://shopify/Location/70021218381', // Shopify requires locationId
availableQuantity: 100, // Available quantity must be specified
}
],
optionValues: [
{
name: "Size", // Option name is "Size"
optionId: sizeOptionId, // Dynamically obtained optionId for "Size"
optionName: size, // Size value (S, M, L, XL, XXL)
}
],
};
});
// Create Product Variants Bulk Mutation
const createVariantsMutation = {
query: `mutation productVariantsBulkCreate($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
productVariantsBulkCreate(productId: $productId, variants: $variants) {
product {
variants(first: 10) {
edges {
node {
id
sku
price
inventoryItem {
id
sku
}
}
}
}
}
userErrors {
field
message
}
}
}`,
variables: {
productId: productId,
variants: variants, // Passing variants to be created
},
};
const variantsResponse = await axios.post(
`https://${shop}/admin/api/2024-07/graphql.json`,
createVariantsMutation,
{
headers: {
'X-Shopify-Access-Token': accessToken,
'Content-Type': 'application/json',
},
}
);
if (variantsResponse.data.errors) {
console.log('GraphQL Errors in variants mutation:', JSON.stringify(variantsResponse.data.errors, null, 2));
return res.status(400).json({ error: 'GraphQL errors in variants mutation', details: variantsResponse.data.errors });
}
console.log('Variants added successfully.');
// Return final response with all product data
return res.status(201).json({
message: 'Product created successfully with media, options, and variants.',
productId,
mediaResponse: mediaResponse.data,
optionsResponse: optionsResponse.data,
variantsResponse: variantsResponse.data,
});
} catch (error) {
// Log the full error if something goes wrong
console.error('Error creating active product in Shopify:', error.response ? error.response.data : error.message || error);
return res.status(500).send('Error creating active product');
}
});