Skip to main content
cat ~/articles/my-first-go-module-go-api-problem.md

My First Go Module - go api problem

Explore the journey of building the first Go Module for error handling in APIs. Simplify error handling in GoLang with this module.

Steve McDougall
Steve McDougall
Backend Engineer & Developer Advocate
7 min read
#go #api-development #error-handling #go-modules

I have been playing with GoLang on and off now for around 3 years, but never really had chance to use it the way I wanted to. However, recently with a new client we needed to start building high throughput microservices for their distributed warehouse system. This was the moment I was waiting for.

I spent a little time designing the architecture for how we were going to achieve the scale and load needed to achieve their goals, a nice mixture of gRPC services with sensibly placed REST APIs for the client facing interfaces. One thing that was obviously clear, was that we would need to find a nice way to handle, track and explain errors that may occur in the system. In PHP I typically use a fantastic package called API Problem which is RFC compliant and handles errors very nicely.

While getting my initial Go service up and running I had a google around to try and find something similar enough to the PHP package I like so much, but struggled to find anything close enough. So I decided it was time to build my first Go Module. Exciting news for me, not only was I finally getting stuck in with building Go services, but I was also already contributing to the open source community for GoLang!

The basis of the module was quite simple, unlike PHP - there are no classes or objects, so all I really needed was a way to build an API problem message and return this as a response from the API. The things that were going to be useful here were:

  • Title: A short human readable error to explain what went wrong
  • Detail: A longer form explanation of the error
  • Status: The HTTP Status Code for the error
  • Code: An internal reference Code that we could document and track through API logs to understand failure points.
  • Meta: A simple key value map that could help further explain the problems going on.

So this didn’t need to be complicated, but I needed to build something as all of my services would need this functionality if they were public facing APIs.

type APIProblem struct {
  Title string `json:"title,omitempty"`
  Detail string `json:"detail,omitempty"`
  Status string `json:"status,omitempty"`
  Code string `json:"code,omitempty"`
  Meta *map[string]interface{} `json:"meta,omitempty"`
}

In essence there was nothing more to do! I had a struct I could build when my API hit an error, and all I needed to do was marshal this into JSON and return response to any client interfaces.

Using this struct was as simple to use as it was to write:

type server struct{}

func main() {
  s := &server{}
  http.Handle("/", func(rw http.ResponseWriter, r *http.Request) {
    if dbc := db.Where("email = ?", "[email protected]").First(&user); dbc.Error != nil {
      respondWithJSON(
        rw,
        http.StatusBadRequest,
        &APIProblem{
          Title:  "Invalid Credentials",
          Detail: "Unable to verify user credentials",
          Status: strconv.Itoa(http.StatusBadRequest),
          Code:   "USER-001-001",
        },
        "application/problem+json",
      )
      return
    }
  })

  log.Fatal(http.ListenAndServe(":8080", nil))
}

func respondWithJSON(rw http.ResponseWriter, code int, payload interface{}, contentType string) {
  response, _ := json.Marshal(payload)
  rw.Header().Set("Content-Type", contentType)
  rw.WriteHeader(code)
  rw.Write(response)
}

So for my first Go Module, it was pretty simple - but it solved a problem I knew I was going to face! Feel free to check out the source code and install instructions on the GitHub Repository

Steve McDougall - Backend Engineer & Developer Advocate

About Steve McDougall

Backend engineer specializing in Laravel, API design, and developer tooling. Building scalable systems and better developer experiences one commit at a time.

Enjoyed this article?

Subscribe to get new posts on Laravel, API design, and developer tooling right in your inbox.

Related articles

  • Sevalla on the Command Line

    Build a beautiful Go-powered CLI tool to manage your Sevalla apps directly from the terminal — no browser, just clean, fast, TUI driven control.

  • API Versioning in Laravel - All you need to know

    All you need to know about API Versioning. What is it, what types of versioning exist, how are they used and why you might need it?

  • Making APIs the Right Way

    All you need to know about API Versioning. What is it, what types of versioning exist, how are they used and why you might need it?

  • How I develop applications with Laravel

    Learn a unique Laravel development workflow; Build a to-do API with a step-by-step guide, leveraging Laravel's versatile tools like Livewire, and a systematic approach from data modeling to API creation.