gatsby-source-mercadolibre
Version:
GatsbyJS plugin that pulls MercadoLibre data into GraphQL.
220 lines (206 loc) • 6.19 kB
JavaScript
const { createRemoteFileNode } = require("gatsby-source-filesystem");
const fetch = require("node-fetch");
const apiHost = "https://api.mercadolibre.com";
// Get product main data
// Documentation: https://api.mercadolibre.com/items/:id#options
exports.getCompleteProductData = itemID => {
return fetch(`${apiHost}/items/${itemID}`)
.then(response => response.json())
.then(allProductData => allProductData)
.catch(err =>
console.log(
"An error ocurred while fetching a product from Mercado Libre.",
err.code
)
);
};
// Query the /pictures/:id endpoint
// and import the largest image from
// the variations provided,
// so they can be processed by transformer plugins
exports.importAndCreateImageNodes = async data => {
if (!data.productPictures || data.productPictures.length === 0) {
return;
}
let picturesToProcess = data.productPictures;
if (data.totalProducts > 300) {
// Note: We are currently limiting to 3 images per product on their lowest size
// due to a bug that happens when importing
// several images and the build hangs on "souce and transform nodes..."
// It usually fixes the problem but large stores
// might still fail
// https://github.com/gatsbyjs/gatsby/issues/6654
picturesToProcess = data.productPictures.filter((p, i) => i < 3);
}
const largestPictures = data.productPictures.map(async pic => {
const image = await fetch(`${apiHost}/pictures/${pic.id}`)
.then(res => {
if (res.status === 200) {
return res.json();
} else {
console.log("Response not 200");
}
})
.catch(() => {
console.log("Fetching image for product failed =>", data.productName);
});
if (image) {
const largest = image.variations && image.variations[0];
image.variations && data.totalProducts > 300
? image.variations[image.variations.length - 1]
: image.variations.find(i => i.size === image.max_size);
if (largest) {
return {
url: largest.secure_url,
id: image.id
};
}
}
});
try {
async function createNodes() {
let nodes = [];
const pictures = await Promise.all(largestPictures);
for (const pic of pictures) {
if (pic) {
const node = await createImageNode(pic, data);
if (node) {
nodes.push(node);
}
}
}
return nodes;
}
return createNodes();
} catch (error) {
return [];
}
};
exports.importAndCreateThumbnailNode = async data => {
if (!data.thumbnail) {
return;
}
const thumbnail = await fetch(`${apiHost}/pictures/${data.thumbnail.id}`)
.then(res => {
if (res.status === 200) {
return res.json();
}
})
.then(image => {
if (image) {
const largest =
image.variations &&
image.variations.find(i => i.size === image.max_size);
if (largest) {
return {
url: largest.secure_url,
id: image.id
};
}
}
})
.catch(error => {
console.log("thumbnail image failed", error.code);
});
if (thumbnail) {
return createImageNode(thumbnail, data);
}
return false;
};
async function createImageNode(pic, data) {
let fileNode = null;
if (pic && pic.url && data.productID) {
try {
fileNode = await createRemoteFileNode({
url: pic.url,
parent: data.productID,
store: data.store,
cache: data.cache,
createNode: data.createNode,
createNodeId: () => `ml-image-${data.productID}-${pic.id}`
});
} catch (e) {
console.log(`Error importing image from MercadoLibre - ${e}`);
}
if (fileNode) {
return { image___NODE: fileNode.id };
}
return;
}
}
// Helper function that processes a product to match Gatsby's node structure
exports.processProduct = (product, createNodeId, createContentDigest) => {
const nodeId = createNodeId(`ML-Product-${product.id}`);
const nodeContent = JSON.stringify(product);
const nodeData = Object.assign({}, product, {
id: nodeId,
parent: null,
children: [],
internal: {
type: `MercadoLibreProduct`,
content: nodeContent,
contentDigest: createContentDigest(product)
}
});
return nodeData;
};
// Seller data
exports.createSellerNode = (data, createNodeId, createContentDigest) => {
const nodeId = createNodeId(`ML-Seller`);
const nodeContent = JSON.stringify(data);
const nodeData = {
id: nodeId,
seller: data,
parent: null,
children: [],
internal: {
type: `MercadoLibreSeller`,
content: nodeContent,
contentDigest: createContentDigest(data)
}
};
return nodeData;
};
// Store wide available filters
exports.createStoreFiltersNode = (data, createNodeId, createContentDigest) => {
const nodeId = createNodeId(`ML-StoreFilters`);
const nodeContent = JSON.stringify(data);
const nodeData = {
id: nodeId,
filters: data,
parent: null,
children: [],
internal: {
type: `MercadoLibreFilters`,
content: nodeContent,
contentDigest: createContentDigest(data)
}
};
return nodeData;
};
// Get the product's description
// Documentation: https://api.mercadolibre.com/items/#options
exports.getItemDescription = itemID => {
return fetch(`${apiHost}/items/${itemID}/description`)
.then(description => description.json())
.catch(() => {
console.log(
`\n ℹ️ Product with id ${itemID} didn't provide a description from the API.`
);
});
};
// Get the product's category information
// Documentation: https://developers.mercadolibre.com.ar/en_us/categories-attributes
exports.getCategoryData = categoryID => {
return fetch(`${apiHost}/categories/${categoryID}`)
.then(category => category.json())
.then(category => ({
category_id: category.id || "",
category_name: category.name || "",
children_categories: category.children_categories || [],
path_from_root: category.path_from_root || []
}))
.catch(e => {
return "";
});
};