Article cover image

Syncing Swell Ecommerce data into Prismic

  • Claudio
    Claudio
    Director of Engineering

A key feature of composable architecture is the ability to piece together different services, data, and content in your project. While this allows for flexible and iterative development, often we find ourselves wanting to sync data across these isolated services.

An example is an Ecommerce site that pulls product data (prices, images, descriptions, etc..) from an Ecommerce platform but the site also contains marketing pages for these products that are built via a CMS. The CMS must also have access to the product information and ideally this would not be manually entered into the CMS because your team would have to manage product data in two places. This would cause more headache for content editors, and the chances of outdated product data showing up on your marketing pages would drastically increase. A solution to this problem can be found when using Swell and Prismic for Ecommerce and CMS content respectively. We’ll utilize Swell’s webhook functionality to trigger the syncing of our data and then push that data to Prismic via their Integration Fields feature.

Swell

Swell is a powerful Ecommerce platform, offering native subscriptions, great Developer Experience, and so much more. You can add a webhook in your swell dashboard at /admin/settings/webhooks. In this example we want to sync product information to Prismic, therefor we’ll set the webhook to fire when a product is created, deleted, or updated. Make sure to fill in the url and point it to your endpoint that will handle the POST request that is triggered by the webhook.

Image for Syncing Swell Ecommerce data into Prismic

Prismic

Prismic is a headless CMS solution that allows development teams to build out a fully customizable content system and marketing teams to seamlessly create, update, and delete content as needed. In order to accept data into Prismic we’ll need to use the Integration Fields feature. At the time of writing this, this feature is still in beta so you may need request access via the Prismic community forum. Once the Integration Fields feature has been activated in your project you will see the Integration Fields tab under your project settings in Prismic. We’ll be using the Custom API option in order to sync with Swell.

Image for Syncing Swell Ecommerce data into Prismic

We'll walk through the “Push data to Prismic” option as this will allow us to sync the changed data to Prismic when it is changed in Swell. Prismic also offers a “Pull data from my endpoint” option, where you set up an endpoint that Prismic will call every 30 minutes, but you also have to deal with pagination for syncing more than 50 items at a time. Choose your Catalog Name and add a description and then click “create my integration field”. After that Prismic will generate an Endpoint and Token for your Integration Field.

Image for Syncing Swell Ecommerce data into Prismic

Creating the endpoint

Swell will make a POST request to our endpoint when a product is either created, deleted, or update and will provide the product id and the event that triggered the webhook.

Prismic requires some fields in order to create or update an Integration Field item, which are:

"id": "my_item_id",
"title": "Item Title",
"description" : "Description of the item.",
"image_url" : "http://...",
"last_update" : 1509364426938,

These fields are required and if not provided the request will fail. Note that these fields will not be available in Prismic but used as meta-data only. Everything inside the blob object will be available to your project when fetching this data from Prismic.

Here’s an example of an endpoint in a SvelteKit project that handles the Swell webhook request and syncs our data to Prismic:

import { error } from '@sveltejs/kit'
import { PUBLIC_SWELL_ID, PUBLIC_SWELL_KEY } from '$env/static/public'
import swell from 'swell-js'

export const POST = async ({ request }) => {
	try {
		swell.init(PUBLIC_SWELL_ID, PUBLIC_SWELL_KEY)

		const {
			data: { id },
			type,
		} = await request.json()

		if (!id) {
			throw error(404, 'no product id provided')
		}
		
		// Delete product in Prismic
		if (type === 'product.deleted') {
			const response = await deleteIntegrationField(id)
			return new Response(String(response))
		}

		// Fetch products from Swell by id
		const { count, results } = await swell.products.get({
			id,
		})

		if (count === 0) {
			throw error(404, 'no products returned from Swell')
		}
		
		// Create/Update products in Prismic
		const response = await createOrUpdatePrismicIntegrationFields(results)
		return new Response(String(response))

		
	} catch (err) {
		return new Response(String(err))
	}
}
// deleteIntegrationField.js
import {
	PRISMIC_ENDPOINT,
	PRISMIC_TOKEN
} from '$env/static/private'

export default async function deleteIntegrationField(productId) {
	const response = await fetch(`${PRISMIC_ENDPOINT}/deleteItems`, {
		method: 'POST',
		headers: {
			Authorization: `Bearer ${PRISMIC_TOKEN}`,
			'Content-Type': 'application/json'
		},
		body: JSON.stringify([productId])
	})

	return response
}
// createOrUpdate.js
import {
	PRISMIC_ENDPOINT,
	PRISMIC_TOKEN
} from '$env/static/private'

export default async function createOrUpdatePrismicIntegrationFields(results) {
	// Fields inside of "blob" will be available in Prismic, the rest is metadata required by prismic
	const fieldsToPushToPrismic = results.map(
		({
			images,
			name,
			description,
			price,
			orig_price,
			sale,
			slug,
			id,
			meta_title,
			meta_description
		}) => ({
			id,
			title: name,
			description,
			image_url: images?.[0]?.file?.url,
			last_update: Date.now(),
			blob: {
				description,
				id,
				images,
				name,
				orig_price,
				price,
				sale,
				slug,
				meta_title,
				meta_description
			}
		})
	)

	const response = await fetch(PRISMIC_ENDPOINT, {
		method: 'POST',
		headers: {
			Authorization: `Bearer ${PRISMIC_TOKEN}`,
			'Content-Type': 'application/json'
		},
		body: JSON.stringify(fieldsToPushToPrismic)
	})

	return response
}

In our endpoint we’re interested in 2 properties from the swell webhook, that’s the type (event that triggered the webhook), and id (the id of the product that was just created, updated, or deleted).

If the type === 'product.deleted' then we make a POST request to our integration field endpoint and add /deleteItems to the end of the url. Note you’ll need to pass your integration field token as an Authorization header when making any requests to your Integration Field endpoint. This just takes an array of id’s and will delete those items from your Integration Field catalogue.

If the type !== 'product.deleted' we know we will be pushing new product data to Primsic. To do this we make a call to swell using the swell-js SDK to get the product data using the id passed via the webhook request. Then we map over the product results returned by our call to swell, returning the meta-fields required by Prismic, and our blob object of data we want to be available from Prismic. We then make a POST request to our Prismic integration field endpoint and supply our array of products data.

Using our custom data

After you set up the Integration Field in Prismic you'll notice a new field with the catalogue name and description you entered earlier is now available to use in your custom types and slices.

Image for Syncing Swell Ecommerce data into Prismic

Now we can use this field in places where we need product data knowing that it will be in sync with our Swell data.