github repo: github.com/sandrofi84/camerashop
My first project left me wanting to explore Gatsby’s capabilities further.
Gatsby is a static site generator, but the websites it creates are all but static. While the files on the server are indeed static, the website becomes dynamic once it is loaded in the browser. The reason for this is that React is at its core, so Gatsby takes advantage of React’s hydration feature. This allows you to make API calls from the browser to pull new content in, while retaining all the advantages of a static website - fast loading, great SEO and higher security.
For my second project I was looking for something a little more challenging, but that could be a good use case for a real-world scenario.
I decided to make an e-commerce website for a small business.
At this point the main question was: how to manage payments? I could have built a shopping cart myself, but going down this route would have meant running a server and a database - where to save transaction and user data - with all the security-related problems that this brings.
I wanted to build something that was not only easy to manage, but also not expensive, as I had the needs of a starting business in mind.
The Shopping Cart
Enter Snipcart - a very simple shopping cart you plug into your website and it takes care of the whole check-out process. It also has a backend where you can manage your inventory, run abandoned-cart recovery campaigns, check sales stats and more.
You cannot create products directly in Snipcart’s backend. To load them into its system - and be able to manage the stock - each product has to have its own page on your website, at which point Snipcart can detect it - by crawling the pages - and load it in the system.
Gatsby can generate pages programmatically, using GraphQL to pull all the information from either local files - markdown works great - or remotely - from a database through a server or a CMS. For usability’s sake I decided for the latter.
Contentful was my choice, as it allows to create/modify and store the products’ information along with images easily, and it integrates well with Gatsby through a plugin. I implemented a webhook that triggers a build of the site whenever a new asset - product or blog post - is published on the CMS.
Now, once your products are loaded into Snipcart’s backend - and you have added stock amounts - you can query for product availability to show the customers every time they open the shop page. I do this using a serverless function, which is one of the services offered by Vercel, the platform I deployed the website to.
A Stateful Layout
I implemented a filtering and a sorting system for shop products to make the shop page easier to navigate. This meant putting in place a state management system at App level - as opposed to just in the Shop page - if I wanted to persist filter/sort preferences through page changes. This is done in Gatsby by wrapping all pages in a component - usually the layout - which would hold state info and provide it to its children. I used Immer for state management, it is very easy to use and works great for a simple website like this.
The website, at this point, was fully functional.
But there was one thing that was bugging me.
When you add an item to Snipcart’s shopping cart, it will inform you in the case that the item is no longer available, because it checks against your stock availability in its system, so there is no chance that somebody buys a product that is not available anymore. But - since we query for the latest product availabilty only upon opening the shop page - in the case where a product is purchased while you were browsing the shop, you would still be able to add it to the cart, only to have Snipcart inform you that the item is no longer available.
This would cause a bad customer experience.
I wanted to show the actual product availability in real-time.
After some research, I decided to implement a subscription system based on Websockets technology.
The idea was that, upon opening the Shop page, the browser would not only get the latest stock availability from Snipcart, but it would also establish a connection via Websockets to a server, which would send a message every time a product is successfully purchased - prompting the browser to check the stock again.
There were a few different ways I could have gone about this, all with pros and cons - not the least of which was the cost, in my case - but I wanted to try AWS AppSync to learn something new.
AppSync is basically a GraphQL server you can configure, which clients can connect to via Websockets to subscribe for content that is published in real-time - this is known as pub/sub pattern. The new content is published through GraphQL mutations, which you can make via an HTTP post request.
Snipcart allows you to configure a webhook so that, when a purchase is completed, it will send an HTTP post request - containing all the information about the purchase - to an endpoint of your choice.
I hooked it up with a NodeJS server that would request the new stock and then prompt a mutation on AppSync, which would, in turn, send the new stock to each client to check for stock availability.
The most challenging part of the project was deciding what structure made more sense for the real-time updates to the Shop page. There are some platforms that offer websocket-as-a-service - like Pusher, Ably or Piesocket - which would have made more sense in a JAMStack architecture. But I wanted to challenge myself and learn something, so I went with a NodeJS server connected to AWS AppSync, which is highly scalable - in case the business takes off!