Connecting Algolia to Cosmic JS for Awesome Search Functionality

Written by tonyspiro | Published 2020/03/12
Tech Story Tags: web-development | reactjs | javascript | cms | api | programming | nodejs | cosmicjs

TLDR Using Cosmic JS’s Webhooks, we can sync Algolia with Cosmic JS to provide fast and powerful search functionality to our projects. The demo App was built with React.js and an Express.js server. There are four main steps: Create an Algoliasearch App, create Cosmic JS Webhook and create API endpoints. Add search widgets to our App and use them to keep the Cosmic JS backend synced. The next step is setting up your server to receive requests and use these endpoints to receive the CosmicJS Webhook requests.via the TL;DR App

Using Cosmic JS’s Webhooks, we can sync Algolia with Cosmic JS to provide fast and powerful search functionality to our projects.

TL;DR

Intro

If you’ve ever tried to implement search yourself, then you know it can be difficult. Thankfully, Algolia has created a product that makes it easy. In this article we’re going to go over how you can connect Algolia to your Cosmic JS backend and add it to your Apps. The demo App was built with React.js and an Express.js server. If you’re using something different, you can still follow this pattern. Just modify it for your use-case.
There are four main steps:
  1. Create an Algolia App
  2. Create Cosmic JS Webhooks
  3. Create API endpoints to receive the Cosmic JS Webhook POST requests
  4. Add search widgets to our App

Part 1 — Create an Algolia App

Navigate to https://www.algolia.com. Log in or sign up for a (free) account.
Once you’ve logged in, navigate to the Dashboard.
In the Dashboard, click ‘NEW APPLICATION’.
Give your App a name and click ‘CREATE’.
The next page will ask you to choose a region. Pick the closest one. Then click ‘Continue’.
You should now see the Dashboard for your newly created App. Click ‘API Keys’ on the left side of the screen. This is a list of API Keys that you will need for later steps.

Part 2 — Create Cosmic JS Webhooks

Log in to your Cosmic JS account and go to your Bucket.
Select ‘Settings’, then ‘Webhooks’ in the Dashboard menu.
You should connect three different Webhooks. Replace the endpoints with whatever you’d like them to be for your project
  1. Event: Object created and published; Endpoint — 
    https://<__YOUR_DOMAIN__>/api/algolia/create
  2. Object edited and published; Endpoint — 
    https://<__YOUR_DOMAIN__>/api/algolia/edit
  3. Object deleted; Endpoint — 
    https://<__YOUR_DOMAIN__>/api/algolia/delete
Click ‘Save Webhooks’. Now your server will receive POST requests whenever an Object is created, edited, or deleted. The next step is setting up your server to receive those requests and use them to keep Algolia synced.

Part 3 — Create API endpoints to receive the Cosmic JS Webhook POST requests

The demo App uses a Node.js Express server. Here’s the code:
/* eslint-disable no-console */
require('dotenv').config({ path: './.env.production' });
const express = require('express');
const bodyParser = require('body-parser');
const corser = require('corser');
const next = require('next');
const routes = require('./routes');
const algoliasearch = require('algoliasearch');
const convertDataToAlgoliaObject = require('./utils/convertDataToAlgoliaObject');
const fetch = require('isomorphic-fetch');

const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handler = routes.getRequestHandler(app);

const client = algoliasearch(
  process.env.ALGOLIA_APPLICATION_ID,
  process.env.ALGOLIA_ADMIN_API_KEY,
);
const itemsIndex = client.initIndex('items');

app.prepare()
  .then(() => {
    const server = express();

    server.use(corser.create());
    server.use(bodyParser.json());

    // ---------- API endpoints for synchronizing Algolia -----------

    server.post('/api/algolia/create', (req, res) => {
      const { data } = req.body;
      if (data.type_slug === 'items') {
        const algoliaObject = convertDataToAlgoliaObject(data);
        itemsIndex.addObject(algoliaObject)
          .catch(err => console.error(err));
      }
      res.status(200).send();
    });

    server.post('/api/algolia/edit', (req, res) => {
      const { data } = req.body;
      if (data.type_slug === 'items') {
        const algoliaObject = convertDataToAlgoliaObject(data);
        itemsIndex.addObject(algoliaObject)
          .catch(err => console.error(err));
      }
      res.status(200).send();
    });

    server.post('/api/algolia/delete', (req, res) => {
      const { data } = req.body;

      // data is an Array of one or more Object _ids
      itemsIndex.deleteObjects(data)
        .catch(err => console.error(err));
      res.status(200).send();
    });

    server
      .listen(port, (err) => {
        if (err) throw err;
        console.log(`> Ready on http://localhost:${port}`);
      });
  });
First, an algoliasearch client is created. It uses the Algolia Application ID and Admin API Key (which can be found in your Algolia App Dashboard).
Then endpoints are created for each Webhook that we’d like to receive from Cosmic JS. The Webhook POST requests include the Object their it’s body. A custom ‘convertDataToAlgoliaObject’ utility function is used to convert that Cosmic JS Object into an object formatted for Algolia. Here’s the code for ‘convertDataToAlgoliaObject’:
const convertDataToAlgoliaObject = (data) => {
  let asin;
  let brand;
  let categories;
  let featured;
  let price;
  let thumbnail;

  data.metafields.forEach((metafield) => {
    switch (metafield.key) {
      case 'asin':
        asin = metafield.value;
        break;
      case 'brand':
        brand = metafield.value;
        break;
      case 'categories':
        categories = metafield.value && metafield.value.split(',');
        break;
      case 'options':
        featured = metafield.value.includes('Featured');
        break;
      case 'price':
        price = metafield.value;
        break;
      case 'thumbnail':
        thumbnail = metafield.value;
        break;
      default:
        // Do nothing
    }
  });

  return {
    asin,
    brand,
    categories: categories || [],
    content: data.content,
    createdAt: data.created_at,
    featured,
    modifiedAt: data.modified_at,
    objectID: data._id, // eslint-disable-line no-underscore-dangle
    price,
    publishedAt: data.published_at,
    slug: data.slug,
    thumbnail,
    title: data.title,
  };
};

module.exports = convertDataToAlgoliaObject;
This function will be different for each project. You basically just want to extract the information that will be ‘searchable’.
Now, Algolia’s algoliaseasrch library can be used to upload, edit, or delete the corresponding entry in Algolia.
The backend setup is complete! You should note, however, that no syncing will take place until you deploy your App. The custom API endpoints you created don’t exist yet, so the Algolia Webhook POST requests won’t be intercepted.
Part 4 — Add search widgets to our App
Not only does Algolia provide awesome search functionality, they also provide many libraries that can be used to display your data. I used their React Instant Search library for the demo project. It provides React components that are essentially plug-and-play. You can customize their styling with your own CSS. The documentation is very well-written, so there’s no need to repeat it here.
Conclusion
Hopefully, you found this article helpful. If something isn’t clear, check out the Cosmic JS or Algolia documentation. They’re both great!
This article originally appears on the Cosmic JS website.

Written by tonyspiro | CEO & Co-Founder of Cosmic JS
Published by HackerNoon on 2020/03/12