A guide to Golang e-commerce

A guide to Golang e-commerce

<strong>Get your e-commerce site up and running with this Go-powered CMS tutorial</strong>

Get your e-commerce site up and running with this Go-powered CMS tutorial

“We haven’t played with Go in a while.”

Our lead developer, reflecting on our content roadmap.

“I haven’t worked with Go at all,” I think to myself.

Today, I’ll give it a go (yeah, I know 🤦‍♂️) by exploring the Golang ecosystem and the e-commerce possibilities it offers.

I’ll then show you how to craft your own Go-powered online shop with the help of Ponzu CMS.

Tutorial steps:

  1. Setting up Ponzu CMS.
  2. Creating the store frontend with a Go static site generator.
  3. Deploying the website to Netlify.
  4. Enabling e-commerce capabilities with Snipcart.

Let’s first take a step back and immerse ourselves in the Golang universe.

Is Golang any good for e-commerce?

What’s Go?

I think it’s still legitimate to call Go an up-and-coming programming language, since the developer community defines it as one of the languages it most wishes to learn. It also ranks as the fifth most loved one, higher than JavaScript and C# amongst others.

This post isn’t about learning the language. If you feel like you need a proper introduction to Golang’s strengths & weaknesses, read this excellent post.

Take Hugo for instance, one of the most popular static site generators out there. Widely recognized as the fastest of its kind, it’ll generate a neat blog or e-commerce frontend in no time.

Go e-commerce backend solutions

Some of these tools are specifically made to generate online shops and e-commerce backends:

  • QOR — A Golang SDK for e-commerce and CMS development. It’s comprised of modules that abstract common features for such systems. Build by Go developers, for Go developers.
  • Ottemo — A mobile-first platform, marketed as “next generation” e-commerce for small and medium companies.
  • Upnext — This one is different as it acts as a payment gateway, leveraging Golang to create faster e-commerce checkouts.

Looking at these e-commerce solutions, you’ll quickly get that they’re mostly massive platforms which might not give you lots of freedom as developers to craft custom shopping UX.

So, are there alternatives here? Two come to mind:

  1. Writing your own custom Go e-commerce API — time-consuming option, but if you have the time and skills to do it right, hats off to you!
  2. Using a third-party solution to integrate with the Go-powered CMS/app of your choice — precisely what I’ll do in the following demo!
If none of these solutions seem to fit your needs, maybe Golang isn’t the right language/framework for your e-commerce backend. Have you thought about trying Node.js, Python/Django or PHP/Laravel?

Technical tutorial: Golang e-commerce with Ponzu CMS

Introduction to Ponzu: a Golang CMS

I’ll use Ponzu CMS to manage the content of my e-commerce app here. In a nutshell, it is an efficient Go-powered open-source HTTP server framework and CMS.

In the words of its creator Steve Manuel:

“It’s easy to use, JSON friendly, and with a fast and concurrent API server. I wanted to pick the parts of other platforms that I liked: take a great CMS backend from WordPress, a developer-first CLI to generate code for me from Rails, and a blazing fast JSON API from Netty.”

It looks like a neat minimalist framework; an excellent choice for small use cases with crazy fast installation and setup, automatic HTTPS configuration, and top-notch performances.

As a headless CMS it allows me to take a JAMstack approach.

The stack will be Go all the way down to the store website: I’ll throw Hugo in the mix as my static site generator.

So, let’s get on with it!

A bit of context for my demo

Sea levels are rising. A rise of a few feet only could get some people’s feet wet. Better be prepared! So let’s start a simple store selling some goods to help people deal with these floods. We’ll have limited stocks, so it will be crucial to keep track of our inventory.


  • Basic knowledge of Go
  • Having Go installed and available in your PATH
  • A Snipcart account (forever free in Test mode)

So let’s get started.

1. Setting up Ponzu CMS and the products API

Having an instance of Ponzu running amounts to executing a few terminal commands:

$ go get -u -v github.com/ponzu-cms/ponzu/...
$ ponzu new snipcart-ponzu
$ cd $GOPATH/src/snipcart-ponzu
$ ponzu build
$ ponzu run --dev-https

Enabling self-signed HTTPS... [DEV]
Server listening on https://localhost:10443 for requests... [DEV]

If your browser rejects HTTPS requests, try allowing insecure connections on localhost.
on Chrome, visit chrome://flags/#allow-insecure-localhost

Server listening at localhost:8080 for HTTP requests...
Visit '/admin' to get started.

Once you’ve done the above, head over to https://localhost:10443/admin.

There’ll be a one-time configuration step before you can get your hands dirty:

You’ll end up in the admin interface. Looks a bit empty, right?

That’s because there still isn’t any content type available. Ponzu provides a command line generator for this.

Let’s create a product content type. Stop the app (CTRL+C) and run the following:

$ ponzu generate content product name:"string" price:"float32" description:"string" image:string:file
$ ponzu build
$ ponzu run --dev-https

When executing the command above, Ponzu creates a product.go file under the content directory of your app. This is the base of this content type definition. You can extend it to make it fit your needs (we’ll get back to that).

Right now, just leave it as-is, restart the app, and go back to the admin dashboard.

You’ll notice that the Product content type is now available in the navigation bar. By clicking it, you access the list of product entries:

Create your first product:


Once created, your new product will instantly be available through Ponzu’s API endpoint:

// https://localhost:10443/api/contents?type=Product

"data": [
"uuid": "62426fee-c78d-4072-b009-92e2d19795c0",
"id": 5,
"slug": "product-62426fee-c78d-4072-b009-92e2d19795c0",
"timestamp": 1536113556000,
"updated": 1536150096023,
"name": "Hot air balloons (pack of 2)",
"price": 23599,
"description": "Best way to go is up! Glide through the air boarding one of these majestic balloons.",
"image": "/api/uploads/2018/09/hot-air-balloons.jpg"

That last step wraps our basic headless CMS setup. Now, the crunchy part!

2. Creating the store website with a Golang SSG

The store will be a Hugo site hosted on Netlify.

You’ll have to install Hugo. Now let’s create your site.

You can do so using the Beautiful Hugo theme and tweaking it a bit.

I won’t go to great lengths explaining the customization since this isn’t our primary focus. A more in-depth walkthrough is covered in this earlier piece.

$ hugo new site myshop.com
$ cd myshop.com
$ cd themes
$ git clone https://github.com/halogenica/beautifulhugo.git beautifulhugo
$ cp ./beautifulhugo/exampleSite/config.toml ../config.toml

Now, you could add a product archetype and run a command like hugo new product/my-awesome-product.md to create content, but you remember this shiny Ponzu product catalog?

You want all of your products to be added automatically, right? Let’s do it this way.

2.1 Generating products for Hugo

What you’ll need to do is code a simple program that will read the products from your Ponzu API and generate Hugo Markdown content files for them.

Since there’s already Ponzu and Hugo in the mix, it just makes sense to use Go for that, doesn’t it?

Just create a simple Go package inside your Hugo site:

# I'm using VS Code here

$ code ponzuImport.go

Here’s the code:

package main
import (

type PonzuProductResponse struct {
Data []PonzuProduct json:"data"
type PonzuProduct struct {
UUID string json:"uuid"
ID int json:"id"
Slug string json:"slug"
Timestamp int64 json:"timestamp"
Updated int64 json:"updated"
Name string json:"name"
Price float32 json:"price"
Description string json:"description"
Image string json:"image"
type HugoProduct struct {
ID string json:"id"
Title string json:"title"
Date time.Time json:"date"
LastModification time.Time json:"lastmod"
Description string
Price float32 json:"price"
Image string json:"image"
Stock int json:"stock"

func (dest *HugoProduct) mapPonzuProduct(
src PonzuProduct,
ponzuHostURL string,
client *http.Client) {
dest.ID = src.Slug
dest.Title = src.Name
dest.Price = src.Price
dest.Description = src.Description
dest.Image = ponzuHostURL + src.Image
dest.Date = time.Unix(src.Timestamp/1000, 0)
dest.LastModification = time.Unix(src.Updated/1000, 0)

func main() {
ponzuHostURL, ok := os.LookupEnv("PONZU_HOST_URL")
if !ok || ponzuHostURL == "" {

var productsEndpoint = ponzuHostURL + "/api/contents?type=Product"

// Fetch products
tr := &amp;http.Transport{
    TLSClientConfig: &amp;tls.Config{InsecureSkipVerify: true}, // this line should be removed in production
client := &amp;http.Client{Transport: tr}
request, err := http.NewRequest(http.MethodGet, productsEndpoint, nil)
if err != nil {
response, err := client.Do(request)
if err != nil {
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
// Parse response JSON
var products PonzuProductResponse
if err = json.Unmarshal(body, &amp;products); err != nil {
// Clear content/product directory
dir, err := os.Getwd()
if err != nil {
if err := os.RemoveAll(dir + "/content/product"); err != nil {
if err := os.MkdirAll(dir+"/content/product", 0777); err != nil {
// Write product content files
for _, sourceProduct := range products.Data {
    var destProduct = HugoProduct{}
    destProduct.mapPonzuProduct(sourceProduct, ponzuHostURL, client)
    entryJSON, err := json.MarshalIndent(destProduct, "", "  ")
    if err != nil {
    file, err := os.Create(dir + "/content/product/" + destProduct.ID + ".md")
    if err != nil {
    writer := bufio.NewWriter(file)
    writer.WriteString(string(entryJSON) + "\n")


The above is pretty simple; it reads through all products and creates a product content file for each one by mapping all relevant fields.

You can test this script by running go build ./ponzuImport.go

3. Deploying to Netlify

You’ll want to generate products on each build, so create the following build.sh script at the root of your website:

#!/usr/bin/env bash

go build -o ./ponzuImport ./ponzuImport.go

Then, configure Netlify to run this script when building your site. Just add this [netlify.toml](https://www.netlify.com/docs/netlify-toml-reference/) file at the root of your website:

publish = "public"
command = "./build.sh"

I'm fixing Hugo version to make sure my theme doesn't break

HUGO_VERSION = "0.47.1"
HUGO_ENV = "production"

You’ll have to set the PONZU_HOST_URL environment variable in your Netlify build configuration. It has to point to your live instance of Ponzu. Whether it’s a ngrok proxy of your local app (when still in development) or a cloud app, it’ll have to be set.

4. Adding e-commerce capabilities to the Go website

Let’s add required Snipcart markup under your layout’s <head> element:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script src="https://cdn.snipcart.com/scripts/2.0/snipcart.js" id="snipcart" data-api-key="{{ .Site.Params.snipcartAPIKey }}"></script>
<link href="https://cdn.snipcart.com/themes/2.0/base/snipcart.min.css" type="text/css" rel="stylesheet" />

Then, render buy buttons like so in your template:

{{ if le .Params.stock 0 }}
<span>Out of stock</span>
{{ else }}
data-item-id="{{ .Params.id }}"
data-item-name="{{ .Title }}"
data-item-price="{{ .Params.price }}"
data-item-image="{{ .Params.image }}"
data-item-description="{{ .Params.description }}">
Add to cart

Now, how about we handle this Stock field seen earlier?

4.1 Enabling inventory management

Snipcart offers inventory management in your Merchant Dashboard.

You don’t want to wait for your products to be purchased before you see them in the dashboard, so let’s crawl them in advance:

Your products are now available in Snipcart! Let’s set stocks for them:

Now, you have to adapt the import script to fetch your products stocks. To do so, you’ll have to use Snipcart’s API.

Open ponzuImport.go and add these two structs:

type SnipcartProductResponse struct {
Items []SnipcartProduct json:"items"
type SnipcartProduct struct {
Stock int json:"stock"

Next, add the following at the end of the mapPonzuProduct function:

// Fetch stock from Snipcart API
var url = "https://app.snipcart.com/api/products?userDefinedId=" + dest.ID
request, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
var apiKey = base64.StdEncoding.EncodeToString([]byte(os.Getenv("SNIPCART_PRIVATE_API_KEY")))
request.Header.Add("Accept", "application/json")
request.Header.Add("Authorization", "Basic "+apiKey)
response, err := client.Do(request)
if err != nil {
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
var products SnipcartProductResponse
if err = json.Unmarshal(body, &products); err != nil {
dest.Stock = products.Items[0].Stock

Note that your Snipcart private API key will have to be set in the SNIPCART_PRIVATE_API_KEY environment variable in your Netlify build configuration.

Neat! From now on, running your build will feed the Stock field as well.

There is one last piece missing to our grand scheme: triggering your Netlify build when data changes.

4.2 Generating build triggers

First, create a Netlify build hook for your website. Any POST request to this URL will trigger a new deployment.

Configuring webhooks in Snipcart is easy. Paste the URL in the Webhooks configuration page of your Merchant Dashboard:

You also want to call this webhook when a change occurs in your Ponzu data. Ponzu CMS offers a handful of extension points using interfaces.

Let’s extend your product content type definition by defining save hooks. Head back to your Ponzu app and add the following to content/product.go:

func (p *Product) AfterAdminCreate(res http.ResponseWriter, req *http.Request) error {
return nil
func (p *Product) AfterAdminUpdate(res http.ResponseWriter, req *http.Request) error {
return nil
func (p *Product) AfterAdminDelete(res http.ResponseWriter, req *http.Request) error {
return nil
func sendWebHook() {
url := os.Getenv("NETLIFY_BUILD_HOOK_URL")
resp, err := http.Post(url, "application/json", nil)
if err != nil {
} else {
log.Println("Webhook called successfully at " + url + " with result " + resp.Status)

Aaaaaand you’re all set! You now have fresh Golang JAMstack e-commerce setup with inventory management. How cool is that?

Live demo & GitHub repo

See the live demo here.
See GitHub repo here.

Closing thoughts

Ponzu is great. The creator put a lot of thought into making the developer journey as simple as possible. Seamless HTTPS certificate setup through Let’s Encrypt is fantastic. The build process produces a native executable that you can run anywhere.

For the production environment, I faced an issue with Heroku’s buildpack for Go — wasn’t playing well with Ponzu’s structure. I recommend running your Ponzu app in Docker.

With some hurdles here and there, I spent about two days building this demo, including the learning curve. A more seasoned Go developer should get through this way faster.

To push this tutorial further? Ponzu CMS supports HTTP/2.0, which comes with a cool feature named Server Push. When building an SPA backed by Ponzu, you can reduce the amount of remote calls you make to the backend by using Server Push to bundle multiple payloads of data that the client is likely to ask in the future!

Got any questions regarding this Snipcart + Golang tutorial? Hit the comments for any comments or questions. And if you enjoyed this post, take a second to 👏 or share on Twitter!

Learn More

Go: The Complete Developer’s Guide (Golang)

Learn How To Code: Google’s Go (golang) Programming Language

Web Development w/ Google’s Go (golang) Programming Language

Build Realtime Apps | React Js, Golang & RethinkDB

Google Golang Masterclass

Advanced Google’s Go (golang) Programming Course

Originally published by Francis Cote at https://medium.freecodecamp.org

Go Programming and Why should you learn Go Language?

Go Programming and Why should you learn Go Language?

Go provides you high performance like C/C++, super efficient concurrency handling like Java and fun to code like Python/Perl. Go with Golang and why go is the best programming language in the world and Why should you learn Go Language?

Why Learn Go Lang - Should I go with 'Go' | Brief Intro to Go Language

Go with Golang and why go is the best programming language in the world.

We will talk about:

  1. Power of GoLang
  2. Is Go for everyone
  3. Who said Go is better than Nodejs
  4. Who are the creators of GoLang
  5. Why GoLang was created by Google
  6. Why Learn of GoLang
  7. Companies using GoLang
  8. What GoLang have and what not
  9. GoLang Garbage Collection
  10. GoLang Concurrency
  11. Recommended Books for Learning GoLang

Rust vs. Go: Should I Rust, or Should I Go

Rust vs. Go: Should I Rust, or Should I Go

Well both Rust and Go provide amazing performance. Should you write you’re next big thing with Rust or with Go? Go is fast and powerful, but it avoids bogging the developer down, focusing instead on simplicity and uniformity. Rust. If on the other hand, wringing out every last ounce of performance is a necessity, then Rust should be your choice. Rust is more of a competitor to C++ than it is with Go.

Should I stay, or should I go?” Great song by the band The Clash. I’m listening to it, right now, while I’m writing this article. The song debuted back in 1982, a long time ago. Back then, I was just a kid exploring a new hobby — programming my Atari 2600. The first video game I ever wrote was written using 6502 Assembly for that console. The compiler for it cost about $65, if I recall, which at the time equated to mowing ~13 or so lawns.

The game was simple: using the joystick, maneuver your spaceship through a randomly generated scrolling cave. The cave walls were sinusoidal, scrolling vertically on the left and right sides of the screen, and you had to make sure your craft didn’t crash into them. I know, I know: Not that sophisticated. But I was only ten or eleven years old at the time.

Despite the “power” of the processor, computing sine values at run-time was simply too much for it. So, using my handy Texas Instruments calculator, I pre-calculated a bunch of the sine values, carefully writing them down on paper, and then entering them in as constants for the game. This greatly enhanced the performance of the game, and made it usable.

So what’s my point? What’s any of this got to do with Rust or Go?

Today’s languages are far more advanced than 6502 Assembly, which make it easier to write complex programs. It took a lot of my time to write that game, and I could do it much faster today, with less code than I did back then. But which language today provides that magic combination of simplicity and power?

Well both Rust and Go provide amazing performance. They both compile to machine code, the Holy Grail of performance. And with today’s processing power, developers can do amazing things with either of these languages. So the question is: Should you write you’re next big thing with Rust or with Go?

With a quick search, you can easily find several articles that go into detail about the differences between the two languages. But the focus of this article is the bang for the buck, that magic combination of performance per line of code.

To put it another way, where is that sweet spot of simple code and top-end performance? And in this case, is it Rust, or is it Go?
There really isn’t any argument: Rust is faster than Go. In the benchmarks above, Rust was faster, and in some cases, an order of magnitude faster.

But before you run off choosing to write everything in Rust, consider that Go wasn’t that far behind it in many of those benchmarks, and it’s still much faster than the likes of Java, C#, JavaScript, Python and so on. So in other words, it’s almost a wash between Rust and Go on the axis of performance. Now, if what you’re building needs to wring out every last ounce of performance, then by all means, choose Rust. But if what you need is top-of-the-line performance, then you’ll be ahead of the game choosing either of these two languages.

So then we’re down to the complexity of the code. This is where things can be muddy since this can be more subjective than performance benchmarks. Let’s look at a simple exercise: building a small web server that prints out “Hello World” when it receives an HTTP request. To do this in Rust, it looks something like this:

use std::net::{TcpStream, TcpListener};
use std::io::{Read, Write};
use std::thread;

fn handle_read(mut stream: &TcpStream) {
    let mut buf = [0u8; 4096];
    match stream.read(&mut buf) {
        Ok(_) => {
            let req_str = String::from_utf8_lossy(&buf);
            println!("{}", req_str);
        Err(e) => println!("Unable to read stream: {}", e),

fn handle_write(mut stream: TcpStream) {
    let response = b"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n<html><body>Hello world</body></html>\r\n";
    match stream.write(response) {
        Ok(n) => println!("Response sent: {} bytes", n),
        Err(e) => println!("Failed sending response: {}", e),

fn handle_client(stream: TcpStream) {

fn main() {
    let port = "8080";
    let listener = TcpListener::bind(format!("{}", port)).unwrap();
    println!("Listening for connections on port {}", port);

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                thread::spawn(|| {
            Err(e) => {
                println!("Unable to connect: {}", e);

Something pretty similar in Go looks like this:

package main

import (

type handler struct{}

func (theHandler *handler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	log.Printf("Received request: %s\n", request.URL)
	log.Printf("%v\n", request)
	io.WriteString(writer, "Hello world!")

const port = "8080"

func main() {
	server := http.Server{
		Addr:    fmt.Sprintf(":%s", port),
		Handler: &handler{},


Now, they are not 100% exactly the same, but they are close enough. The difference between them is ~20 lines of code. Rust definitely forces the developer to consider more, and thus write more code than Go.

Another example: Consider one of the more difficult aspects of software development: multi-threading. When tackling something like this, as you undoubtedly would when building an HTTP server, there’s a lot to think about:

  • You need to ensure everything you design is thread safe (locks)
  • You need to handle communication between threads (channels)
  • You have to design with concurrency and parallelism in mind (threads and routines)

Both Rust and Go handle these hurdles really efficiently, but Go requires less effort. With Rust, you have way more options, and thus more power, when spawning threads. Just look at some of the documentation on this. Here’s just one way to spawn a thread in Rust:

use std::thread;

let handler = thread::spawn(|| {
    // thread code


On the other hand, here’s how to create something similar using Go:

go someFunction(args)

Another crucial part of writing code is handling errors. Here I think Rust and Go are quite similar. Rust enables the developer to handle errors cases through the use of the enum return types: Option<T>and Result<T, E>. The Option<T> will return either None or Some(T) whereas Result<T, E> will return either Ok(T) or Err(T). Given that most of Rust’s own libraries, as well as other third-party libraries, return one of these types, the developer will usually have to handle the case where nothing is returned, or where an error is returned.

Here’s a simple example of the Result type being returned by a function in Rust:

fn foo_divide(a: f32, b: f32) -> Result<f32, &'static str> {
    if b == 0.0 {
        Err("divide by zero error!")
    } else {
        Ok(a / b)
}fn main() {
    match foo_divide(5.0, 4.0) {
        Err(err) => println!("{}", err),
        Ok(result) => println!("5 / 4 = {}", result),

Notice that the Err case must be handled within the match statement.

Go, on the other hand, leaves this more up to the developer, since errors can be ignored using the _. However, idiomatic Go strongly recommends returning an error, especially since functions in Go can return multiple values. Therefore, it’s easy to have functions return their intended value along with an error, if there is one.

Here is the corresponding example from above done in Go:

func fooDivide(a float32, b float32) (float32, error) {
    if b == 0 {
        return 0, errors.New("divide by zero error!")
    }    return a / b, nil
}func main() {
    result, err := fooDivide(5, 4)
    if err != nil {
       log.Printf("an error occurred: %v", err)
    } else {
       log.Printf("The answer is: 5 / 4 = %f", result)

Notice that this line:

result, err := fooDivide(5, 4)

could have been written as

result, _ := fooDivide(5, 4)

In the latter case, the error returned would have been ignored.

Honestly, they’re both pretty similar, except for Rust forcing error checking. Otherwise, there’s little difference, and it’s difficult to find an advantage one has over the other. To my eyes, this is a draw.

I could keep going, digging deeper into other language differences. But the bottom line, from threads, to channels, to generics, Rust provides the developer with more options. In this respect, Rust is closer to C++ than Go. Does this make Rust inherently more complex?

I think so, yes.

So here are my recommendations:

  • Either. If you’re building a web service that handles high load, that you want to be able to scale both vertically and horizontally, either language will suit you perfectly.
  • Go. But if you want to write it faster, perhaps because you have many different services to write, or you have a large team of developers, then Go is your language of choice. Go gives you concurrency as a first-class citizen, and does not tolerate unsafe memory access (neither does Rust), but without forcing you to manage every last detail. Go is fast and powerful, but it avoids bogging the developer down, focusing instead on simplicity and uniformity.
  • Rust. If on the other hand, wringing out every last ounce of performance is a necessity, then Rust should be your choice. Rust is more of a competitor to C++ than it is with Go. Having battled with C++, Rust feels just as powerful but with many happy improvements. Rust empowers developers to have control over every last detail of how their threads behave with the rest of the system, how errors should be handled, and even the lifetime of their variables!
  • Rust. Rust was designed to interoperate with C. Go can as well, but gives up a lot to achieve this goal, and it’s not really its focus.
  • Go. If readability is a requirement, go with Go. It’s far too easy to make your code hard for others to grok with Rust.

I hope you enjoyed reading this!