Author: Amir Tadrisi
To have a successful e-commerce strategy, you need to publish your products on different platforms like Amazon, eBay, and Shopify to make your products available in a wider market. One of the biggest challenges of this strategy is you don't have a single source of truth for your products, and when you have a high number of products, it becomes really hard to manage one product and its attributes on multiple platforms.
In this tutorial, we will see how we can use Strapi to solve this problem.
Prerequisites
- Node 14.19.1: Please, visit Node Previous Releases Page to download node v14 or earlier.
Goals
In this tutorial, we'll learn how having a single source of truth can help with product management. We start by creating a content type for products. Then, we'll import product details from two different sources and save the theme in Strapi. Then, we'll enrich the products in Strapi. We will also build a storefront for our products using Strapi as Product Information Manager.
What is a PIM?
A Product Information Management (PIM) solution is a business application that provides a single place to collect, manage, and enrich your product information, create a product catalog, and distribute it to your sales and eCommerce channels. A PIM solution makes it faster and easier to create and deliver compelling product experiences.
What We're Building
In this tutorial, we'll build a Product Information Manager (PIM) with Strapi, importing products details from 2 data sources:
- Dummyjson API
- Fakestoreapi API
- We will also enrich the products in Strapi and build a custom storefront with Next.js.
- In our Storefront, we pull products from Strapi GraphQL API and build a catalog.
You can find a live demo of the application here.
Step 1: Install and Set up Strapi
The first thing in this stage is the installation and setup of Strapi. To do this, follow the instructions below:
- Open a terminal and run the following command to clone the Strapi repository and install it:
git clone https://github.com/amirtds/strapi-pmi
- Open the
strapi-pmi
directory in your favorite editor and rename the.env.example
file to.env
. Then, open the.env
file and add the following line:
API_TOKEN_SALT=tempkey
Note: For this tutorial, we are using a default value for environment variables; for production, you should change them.
- Next, run the following command to install the dependencies and run Strapi in development mode:
yarn install && yarn develop
After the command is executed, visit http://localhost:1337/ and create an admin user.
Step 2: Create Product Content Type
The next step is to employ the content-type builder. Follow the instructions below:
- After successfully logging in to Strapi, on the left sidebar, under the PLUGINS section, click on the Content-Type Builder button.
- Under the COLLECTION TYPES click on the Create new collection type link and for the Display name, enter
product
. - Let's create fields for our new content type. The product content type will have the following fields:
- name (text)
- description (textarea)
- price (decimal number)
- published (boolean)
- brand (text)
- color (text)
- size (text)
- quantity (integer number)
- discount_price (decimal number)
- discount_start_date (date)
- discount_end_date (date)
- category (text)
- imageUrl (text)
- currency (text)
- bestseller (boolean)
- featured (text) > For more information about the content-type builder please visit Strapi Doc for Introduction to the Content-Type Builder.
Next, let's enable the find
and findOne
queries for products via Strapi GraphQL API.
- Click on the settings link on the left sidebar and then click on the Roles under USERS & PERMISSIONS PLUGIN.
- Click on Public and in the Permissions section, pick Products. Select
find
andfindOne
. - Click on the Save button on the navigation bar.
Step 3: Collect Products Data into Strapi
As we mentioned earlier, we are going to fetch products data from two sources, Dummyjson API and Fakestoreapi API.
Let's create a cron job to fetch these data every day the product doesn't exist in Strapi, we use product
api service to create a new product.
- Open the
strapi-pmi
in your editor, in the config directory, create a new file calledcront-tasks.js
, and add the following code to it:
const fetch = require('node-fetch');
module.exports = {
'0 0 0 * * *': async ({ strapi }) => {
let products = []
// Get all products from dummyjson API
const dummyjsonResponse = await fetch('https://dummyjson.com/products');
const dummyProducts = await dummyjsonResponse.json();
// Append each product to the products array
products.push(...dummyProducts.products);
// Get all products from fakestoreapi API
fakeStoreResponse = await fetch('https://fakestoreapi.com/products');
fakeStoreProducts = await fakeStoreResponse.json();
// Append each product to the products array
products.push(...fakeStoreProducts);
// Loop through each product
products.forEach(async (product) => {
// Check if the product already exists
const existingProduct = await strapi.service("api::product.product").find({
filters: {
name: product.title
}
});
// If the product exists, log it
if (existingProduct.results.length > 0){
console.log(`Product ${product.title} already exists`)
}
else {
// If the product doesn't exist, create it
// create the image
let image = ""
product.image !== undefined ? image = product.image : product.images !== undefined ? image = product.images[0] : image = ""
const createdProduct = strapi.service("api::product.product").create({
data : {
name: product.title,
description: product.description,
imageUrl: image,
price: product.price,
brand: product.brand || '',
color: product.color || '',
size: product.size || '',
quantity: product.quantity || 0,
category: product.category || '',
}
});
}
});
}
}
Take note of the code comments.
- Now, let's enable the cron tasks in Strapi. In the config directory, open
server.js
and replace its content with the following:
const cronTasks = require("./cron-tasks");
module.exports = ({ env }) => ({
host: env('HOST', '0.0.0.0'),
port: env.int('PORT', 1337),
app: {
keys: env.array('APP_KEYS')
},
cron: {
enabled: true,
tasks: cronTasks
},
});
To learn more about Cron Jobs in Strapi, please visit Strapi Doc.
To initialize our server with product data we can run similar code in bootstrap function to create products.
- At the root of the project go to the src folder and open
index.js
file. replacebootstrap(/*{ strapi }*/) {},
with the following:
bootstrap({ strapi }) {
const fetch = require('node-fetch');
let products = []
// Get all products from dummyjson API and append them to the products array
fetch('https://dummyjson.com/products').then(response => response.json()).then(dummyProducts => {
products.push(...dummyProducts.products);
// Get all products from fakestoreapi API and append them to the products array
fetch('https://fakestoreapi.com/products').then(response => response.json()).then(fakeStoreProducts => {
products.push(...fakeStoreProducts);
// Loop through each product
products.forEach(async (product) => {
// Check if the product already exists
const existingProduct = await strapi.service("api::product.product").find({
filters: {
name: product.title
}
});
// If the product exists, log it
if (existingProduct.results.length > 0){
console.log(`Product ${product.title} already exists`)
}
else {
// If the product doesn't exist, create it
// create the image
let image = ""
product.image !== undefined ? image = product.image : product.images !== undefined ? image = product.images[0] : image = ""
const createdProduct = strapi.service("api::product.product").create({
data : {
name: product.title,
description: product.description,
imageUrl: image,
price: product.price,
brand: product.brand || '',
color: product.color || '',
size: product.size || '',
quantity: product.quantity || 0,
category: product.category || '',
}
});
}
});
});
});
}
Take note of the code comments.
- Now run the server, click on Content Manager and select Product under COLLECTION TYPES, you should see a list of all products.
Step 4: Enrich Products Data
Let's enrich one of our products with more data.
- Go to the Product page in the Content Manager and search for
Samsung 49-Inch
product. - Open the product page and add the following data:
-
brand
:Samsung
-
color
:Black
-
size
:49 Inch
-
quantity
:10
-
discount_price
:$799.99
-
discount_start_date
:2023-01-01
-
discount_end_date
:2023-01-05
-
published
:true
-
currency
:USD
-
bestseller
:true
-
featured
:true
- Click on the Save button on the navigation bar.
As you can see, all the fields we filled were empty because we didn't have any data for them in our data sources.
Step 5: Stream Products Data into Sales Channels - Nextjs Storefront
In this step, we will publish our products into a custom storefront powered by Nextjs. Before continuing, please make sure your Strapi server is running.
Clone the storefront project from GitHub.
git clone -b feat/frontend-without-strapi https://github.com/amirtds/my-store-frontend.git
The UI of the storefront is already built. In this step, we are going to integrate our PMI into it to make it work.
- Open the my-store-frontend folder in your editor and create a new file called
.env
at the root of the project with the following content:
STRAPI_GRAPHQL_ENDPOINT = http://localhost:1337/graphql
In the project, we are going to query Strapi Graphql API for products and we are also going to filter products to find featured products to show in the Hero section of the storefront. Now open http://localhost:1337/graphql in your browser (this is Strapi Graphql API and it opens a playground for you to test queries). In the left section paste the following query:
query {
products(pagination: {pageSize: 50}) {
data {
id
attributes {
name
description
price
published
brand
color
size
quantity
discount_price
discount_start_date
discount_end_date
category
imageUrl
currency
bestseller
featured
}
}
}
}
- Click on the Play button and you should see all the products in the right section. We are going to use this query to fetch all of our products from Strapi.
Now let's test another query we are going to use in our storefront.
- Clean the left section and paste the following query:
query {
products(filters: {featured: {eq: true}}) {
data {
id
attributes {
name
description
price
published
brand
color
size
quantity
discount_price
discount_start_date
discount_end_date
category
imageUrl
currency
bestseller
featured
}
}
}
}
- Click on the Play button and you should see the featured product in the right section. We are going to use this query to fetch featured products from Strapi.
Let's go back to our editor and open the storefront project.
- In the
src/pages/index.js
file, look forconst FEATURED_PRODUCT_QUERY =
and replace the"REPLACE_WITH_QUERY"
with the following:
gql`
query {
products(filters: {featured: {eq: true}}) {
data {
id
attributes {
name
description
price
published
brand
color
size
quantity
discount_price
discount_start_date
discount_end_date
category
imageUrl
currency
bestseller
featured
}
}
}
}
`;
- Next look for
const ALL_PRODUCTS_QUERY =
and replace the"REPLACE_WITH_QUERY"
with the following:
gql`
query {
products(pagination: {pageSize: 50}) {
data {
id
attributes {
name
description
price
published
brand
color
size
quantity
discount_price
discount_start_date
discount_end_date
category
imageUrl
currency
bestseller
featured
}
}
}
}
`;
- Next, go to the
src/pages/api/products.js
file and replace the"REPLACE_WITH_QUERY"
with the following:
gql`
query {
products(pagination: {pageSize: 50}) {
id
attributes {
name
description
price
published
brand
color
size
quantity
discount_price
discount_start_date
discount_end_date
category
imageUrl
currency
bestseller
featured
}
}
}
`;
- Open your terminal, navigate to the root of the
my-store-frontend
folder and run the following command to install all the dependencies and run storefront:
npm install && npm run dev
- Visit http://localhost:3000/ in your browser and you should see the storefront with products from Strapi.
Conclusion
In this tutorial, we have learned how we can use Strapi to build a Product Information Manager to have a single source of truth for our products. We used the bootstrap function and cron job to populate product data from different data sources, we could enrich our products with more data that doesn't exist in our data sources. Finally, we enabled Graphql for our products and streamed them into our Nextjs storefront.
We only streamed the products to one sales channel, but we can duplicate the process in Step 5 to stream products to multiple sales channels like Shopify, Magento, etc.
As a practice, you can try creating a Shopify store and stream products to your Shopify store.