Building a Product Information Manager with Strapi
Tags: strapi, cms, pmi, nextjs
Published: 2022-08-01 08:11:57

---
canonical_url: https://strapi.io/blog/how-to-build-a-product-information-manager-using-strapi?utm_campaign=Strapi%20Blog&utm_source=devto&utm_medium=blog
---
**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](https://nodejs.org/en/download/releases/) 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.

![A Breakdown of PMI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aosqva547qa4kavphzpy.png)

## 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](https://dummyjson.com/products)
- [Fakestoreapi API](https://fakestoreapi.com/products)
- 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.
![What we're building](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k7mo9zl22pmx8f5hvkic.png)


You can [find a live demo of the application here](https://my-store-frontend.vercel.app/).

## 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:

1. Open a terminal and run the following command to clone the Strapi repository and install it:
```bash
    git clone https://github.com/amirtds/strapi-pmi
```

2. 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.

3. Next, run the following command to install the dependencies and run Strapi in development mode:
```bash
    yarn install && yarn develop
```
After the command is executed, visit [http://localhost:1337/](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:
1. After successfully logging in to Strapi, on the left sidebar, under the **PLUGINS** section, click on the **Content-Type Builder** button.
2. Under the **COLLECTION TYPES** click on the **Create new collection type** link and for the **Display name**, enter `product`.
3. 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](https://docs.strapi.io/user-docs/latest/content-types-builder/introduction-to-content-types-builder.html).

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` and `findOne`. 
* 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](https://dummyjson.com/products) and [Fakestoreapi API](https://fakestoreapi.com/products).

Let's create a cron job to fetch these data every day the product doesn't exist in Strapi, we use `product` [api service](https://docs.strapi.io/developer-docs/latest/development/backend-customization/services.html#usage) to create a new product.

1. Open the `strapi-pmi` in your editor, in the **config** directory, create a new file called `cront-tasks.js`, and add the following code to it:
```js
    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.

2. Now, let's enable the cron tasks in Strapi. In the **config** directory, open `server.js` and replace its content with the following:
```js
    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](https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/optional/cronjobs.html#creating-a-cron-job).

To initialize our server with product data we can run similar code in [bootstrap](https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/optional/functions.html#bootstrap) function to create products. 

3. At the root of the project go to the **src** folder and open `index.js` file. replace `bootstrap(/*{ strapi }*/) {},` with the following:
```js
      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.

4. 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. 
1. Go to the Product page in the Content Manager and search for `Samsung 49-Inch` product.
2. 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`

3. 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](https://nextjs.org/). **Before continuing, please make sure your Strapi server is running.** 

[Clone the storefront project from GitHub](https://github.com/amirtds/my-store-frontend).
```bash
    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.

1. 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](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
            }
          }
        }
      }
```
2. 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. 

3. 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
            }
          }
        }
      }
```
4. 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. 

5. In the `src/pages/index.js` file, look for `const 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
            }
          }
        }
      }
    `;
```
6. 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
            }
          }
        }
      }
    `;
```
7. 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
            }
          }
        }
      `;
```
8. 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:
```bash
    npm install && npm run dev
```
9. Visit [http://localhost:3000/](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.

[Click here to view the source code for this tutorial.](https://github.com/amirtds/strapi-pmi/tree/feat/products-pmi)