Building a Product Information Manager with Strapi

Strapi - Aug 1 '22 - - Dev Community

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

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

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. What we're building

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:

  1. Open a terminal and run the following command to clone the Strapi repository and install it:
    git clone https://github.com/amirtds/strapi-pmi
Enter fullscreen mode Exit fullscreen mode
  1. 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
Enter fullscreen mode Exit fullscreen mode

Note: For this tutorial, we are using a default value for environment variables; for production, you should change them.

  1. Next, run the following command to install the dependencies and run Strapi in development mode:
    yarn install && yarn develop
Enter fullscreen mode Exit fullscreen mode

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:

  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.

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

  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:
    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 || '',
                            }
                        });
                }
            });
      }
    }
Enter fullscreen mode Exit fullscreen mode

Take note of the code comments.

  1. 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
      },
    });
Enter fullscreen mode Exit fullscreen mode

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.

  1. At the root of the project go to the src folder and open index.js file. replace bootstrap(/*{ 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 || '',
                  }
                });
              }
            });
          });
        });
      }
Enter fullscreen mode Exit fullscreen mode

Take note of the code comments.

  1. 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
  1. 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
            }
          }
        }
      }
Enter fullscreen mode Exit fullscreen mode
  1. 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.

  1. 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
            }
          }
        }
      }
Enter fullscreen mode Exit fullscreen mode
  1. 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.

  1. 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
            }
          }
        }
      }
    `;
Enter fullscreen mode Exit fullscreen mode
  1. 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
            }
          }
        }
      }
    `;
Enter fullscreen mode Exit fullscreen mode
  1. 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
            }
          }
        }
      `;
Enter fullscreen mode Exit fullscreen mode
  1. 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
Enter fullscreen mode Exit fullscreen mode
  1. 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.

Click here to view the source code for this tutorial.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .