RSSAmplifier

Blog

Alex Edwards

Alex Edwards' blog

alexedwards.netRSS feed ↗54 posts

Latest posts

How I use HTMX with Go

When I want to add sprinkles of interactivity to a web application, I'm a big fan of using HTMX . I like that it makes it easy to give interactions a smooth app-like feel, I like that it minimizes the amount of JavaScript that I have to write, and I like that it allows me to keep the consistency and safety of server-side HTML rendering with Go's html/template package. In this post I'm going to run…

Go Experiments Explained

Go often ships with experimental features as part of a release. These experimental features can take different forms: sometimes they're completely new packages in the standard library, sometimes they're changes to the compiler or runtime, or – very occasionally – they can be breaking changes to Go's behavior. Most of the time, the purpose of experimental features is to get real-world…

Go Naming Conventions: A Practical Guide

Choosing the right names in your codebase is an important (and sometimes difficult!) part of programming in Go. It's a small thing that makes a big difference — good names make your code clearer, more predictable, and easier to navigate; bad names do the opposite. Go has fairly strong conventions — and a few hard rules — for naming things. In this post we're going to explain these rules and…

A modern approach to preventing CSRF in Go

Go 1.25 introduced a new http.CrossOriginProtection middleware to the standard library — and it got me wondering: Have we finally reached the point where CSRF attacks can be prevented without relying on a token-based check (like double-submit cookies)? Can we build secure web applications without bringing in third-party packages like justinas/nosurf or gorilla/csrf ? And I think the answer…

The 9 Go test assertions I use (and why)

A few weeks ago Anton Zhiyanov published the blog post Expressive tests without testify/assert . It's a good and well thought-out post, and I recommend giving it a read if you haven't already. In the post, Anton makes the argument for not using packages like testify/assert for your test assertions, and instead creating your own minimal set of assertion helpers to use in your tests. In fact, so…

How to manage configuration settings in Go web applications

When I'm building a web application in Go, I prefer to use command-line flags to pass configuration settings to the application at runtime. But sometimes, the client I'm working with wants to use environment variables to store configuration settings, or the nature of the project means that storing settings in a TOML, YAML or JSON file is a better fit. And of course that's OK — it makes sense…

Organize your Go middleware without dependencies

For many years, I've used third-party packages to help organize and manage middleware in my Go web applications. In small projects, I often used alice to create middleware 'chains' that I could reuse across multiple routes. And for larger applications, with lots of middleware and routes, I typically used a router like chi or flow to create nested route 'groups' with per-group middleware. But since…

When is it OK to panic in Go?

If you've been working with Go for a while, you might be familiar with the Go proverb "don't panic". It's a pithy way of saying: "handle errors gracefully, or return them to the caller to handle gracefully, instead of passing errors to the built-in panic() function". And while "don't panic" is a great guideline that you should follow, sometimes it's taken to mean that you should no-way, never,…

How to manage tool dependencies in Go 1.24+

One of my favourite features of Go 1.24 is the new functionality for managing developer tooling dependencies. By this, I mean tooling that you use to assist with development, testing, build, or deployment – such as staticcheck for static code analysis, govulncheck for vulnerability scanning, or air for live-reloading applications. Historically, managing these dependencies — especially in a…

Eleven tips for structuring your Go projects

When working with Go, you have three main building blocks to help organize your code: files , packages and modules . But as Go developers, one of the common challenges we have is knowing how to best combine these building blocks to structure a codebase. In this post, I'll share a mix of mindset tips and practical advice that I hope will help, especially if you're new to the language. Different…

Implementing an in-memory cache in Go

In almost all web applications that I build, I end up needing to persist some data – either for a short period of time (such as caching the result of an expensive database query), or for the lifetime of the running application until it is restarted. When your application is a single binary running on a single machine, a simple, effective, and no-dependency way to do this is by persisting the…

Demystifying function parameters in Go

In this post we're going to talk about how (and why!) different types of function parameters behave differently in Go. If you're new (or even not-so-new) to Go, this can be a common source of confusion and questions. Why do functions generally mutate maps and slices, but not other data types? Why isn't my slice being mutated when I append to it in a function? Why doesn't assigning a new value to a…

A time-saving Makefile for your Go projects

Whenever I start a new Go project, one of the first things I do is create a Makefile in the root of my project directory. This Makefile serves two purposes. The first is to automate common admin tasks (like running tests, checking for vulnerabilities, pushing changes to a remote repository, and deploying to production), and the second is to provide short aliases for Go commands that are long or…

How to use the http.ResponseController type

One of my favorite things about the recent Go 1.20 release is the new http.ResponseController type, which brings with it three nice benefits: You can now override your server-wide read and write deadlines on a per request basis. The pattern for using the http.Flusher and http.Hijacker interfaces is clearer and feels less hacky. No more type assertions necessary! It makes it easier and safer to…

An introduction to Packages, Imports and Modules in Go

This tutorial is written for anyone who is new to Go. In it we'll explain what packages, import statements and modules are in Go, how they work and relate to each other and — hopefully — clear up any questions that you have. We'll start at a high level, then work down to the details later. There's quite a lot of content in this tutorial, so I've broken it down into the following eight…

A complete guide to working with Cookies in Go

In this post we're going to run through how to use cookies in your Go web application to persist data between HTTP requests for a specific client . We'll start simple, and slowly build up a working application which covers the following topics: Basic reading and writing of cookies Encoding special characters and maximum length Using tamper-proof (signed) cookies Using confidential (encrypted) and…

The 'fat service' pattern for Go web applications

In this post I'd like to talk about one of my favorite architectural patterns for building web applications and APIs in Go. It's kind of a mix between the service object and fat model patterns — so I mentally refer to it as the 'fat service' pattern, but it might have a more formal name that I'm not aware of It's certainly not a perfect pattern (we'll discuss some of the pros and cons later)…

Flow: A tiny but powerful HTTP router for Go

Last year I wrote a new HTTP router for Go called Flow . I've been using it in production on this site and in a couple of other projects since, and I'm pretty happy with how it's working out so decided to share it a bit more widely. My aim with Flow was to bring together my favourite features from other popular routers that I frequently used. It has: A very small and readable codebase (approx. 160…

How to use go run to manage tool dependencies

When you're working on a project it's common for there to be some developer tooling dependencies. These aren't code dependencies, but rather tools that you run as part of the development, testing, build or deployment processes. For example, you might use golang.org/x/text/cmd/gotext in conjunction with go:generate to generate message catalogs for translation, or honnef.co/go/tools/cmd/staticcheck…

Easy test assertions with Go generics

Now that Go 1.18 has been released with support for generics , it's easier than ever to create helper functions for your test assertions . Using helpers for your test assertions can help to: Make your test functions clean and clear; Keep test failure messages consistent; And reduce the potential for errors in your code due to typos. To illustrate this, let's say that you have a simple greet()…

Continuous integration with Go and GitHub Actions

In this post we're going to walk through how to use GitHub Actions to create a continuous integration (CI) pipeline that automatically tests, vets and lints your Go code. For solo projects I usually create a pre-commit Git hook to carry out these kinds of checks, but for team projects or open-source work — where you don't have control over everyone's development environment — using a…

Change URL query params in Go

In this short post we're going to discuss how to add, modify or delete URL query string parameters in Go. To illustrate, we'll look at how to change this URL: https://example.com?name=alice&age=28&gender=female To this: https://example.com?name=alice&age=29&occupation=carpenter If you want to change the URL query string in place : // Use url.Parse() to parse a string into a *url.URL type. If your…

Which Go router should I use?

Note: This post has been fully updated to reflect the new http.ServeMux features released in Go 1.22. When you start to build web applications with Go, one of the first questions you'll probably ask is "which router should I use?" . It's not an easy question to answer, either. You've got http.ServeMux in the Go standard library, and probably more than 100 different third-party routers also…

I18n in Go: Managing translations

Recently I've been building a fully internationalized (i18n) and localized (l10n) web application for the first time with Go's golang.org/x/text packages. I've found that the packages and tools that live under golang.org/x/text are really effective and well designed, although it's been a bit of a challenge to figure out how to put it all together in a real application. Note: Just in case you're…

How to correctly use Basic Authentication in Go

When searching for examples of HTTP basic authentication with Go, every result I found unfortunately contained code which was either out-of-date (i.e. doesn't use the r.BasicAuth() functionality that was introduced in Go 1.4) or failed to mitigate the risk of timing attacks. So in this post, I'd like to discuss how to use it correctly in your Go applications. We'll start with a bit of background…

Custom command-line flags with flag.Func

One of my favorite things about the recent Go 1.16 release is a small — but very welcome — addition to the flag package: the flag.Func() function. This makes it much easier to define and use custom command-line flags in your application. For example, if you want to parse a flag like --pause=10s directly into a time.Duration type, or parse --urls="http://example.com http://example.org"…

Surprises and gotchas when working with JSON

This is a list of things about Go's encoding/json package which, over the years, have either confused or surprised me when I first encountered them. Many of these things are mentioned in the official package documentation if you read it carefully enough, so in theory they shouldn't come as a surprise. But a few of them aren't mentioned in the documentation at all — or at least, they aren't…

How to manage database timeouts and cancellations in Go

One of the great features of Go's database/sql package is that it's possible to cancel database queries while they are still running via a context.Context instance. On the face of it, usage of this functionality is quite straightforward (here's a basic example ). But once you start digging into the details there's a lot a nuance and quite a few gotchas... especially if you are using this…

How to parse a JSON request body in Go

Let's say that you're building a JSON API with Go. And in some of the handlers — probably as part of a POST or PUT request — you want to read a JSON object from the request body and assign it to a struct in your code. After a bit of research, there's a good chance that you'll end up with some code that looks similar to the personCreate handler here: // File: main.go package main import…

Golang Interfaces explained

For the past few months I've been running a survey which asks people what they're finding difficult about learning Go. And something that keeps coming up in the responses is the concept of interfaces . I get that. Go was the first language I ever used that had interfaces, and I remember at the time that the whole concept felt pretty confusing. So in this tutorial I want to do a few things: Provide…

Using PostgreSQL JSONB with Go

PostgreSQL provides two JSON-related data types that you can use — JSON and JSONB . The principal differences are: JSON stores an exact copy of the JSON input. JSONB stores a binary representation of the JSON input. This makes it slower to insert but faster to query. It may change the key order, and will remove whitespace and delete duplicate keys. JSONB also supports the ? (existence) and…

An overview of Go's tooling

Occasionally I get asked “why do you like using Go?” And one of the things I often mention is the thoughtful tooling that exists alongside the language as part of the go command. There are some tools that I use everyday — like go fmt and go build — and others like go tool pprof that I only use to help solve a specific issue. But in all cases I appreciate the fact that they…

How to hash and verify passwords with Argon2 in Go

Thanks to Andreas Auernhammer , author of the golang.org/x/crypto/argon2 package, for checking over this post before publication. If you're planning to store user passwords it's good practice (essential really) to hash them using a computationally expensive key-derivation function (KDF) like Bcrypt, Scrypt or Argon2. Hashing and verifying passwords in Go with Bcrypt and Scrypt is already easy to…

Streamline your Sublime Text + Go workflow

For the past couple of years I've used Sublime Text as my primary code editor, along with the GoSublime plugin to provide some extra IDE-like features. But I've recently swapped GoSublime for a more modular plugin setup and have been really happy with the way it's worked out. Although it took a while to configure, it's resulted in a coding environment that feels clearer to use and more streamlined…

HTTP Method spoofing in Go

A.K.A. HTTP method overriding . As a web developer you probably already know that HTML forms only support the GET and POST HTTP methods. If you want to send a PUT , PATCH or DELETE request you need to resort to either sending a XMLHttpRequest from JavaScript (where they are supported by most major browsers) or implement a workaround in your server-side application code to support 'spoofed' HTTP…

How to build a Serverless API with Go and AWS Lambda

Earlier this year AWS announced that their Lambda service would now be providing first-class support for the Go language, which is a great step forward for any gophers (like myself) who fancy experimenting with serverless technology. So in this post I'm going to talk through how to create a HTTPS API backed by AWS Lambda, building it up step-by-step. I found there to be quite a few gotchas in the…

How to disable http.FileServer directory listings

A nice feature of Go's http.FileServer is that it automatically generates navigable directory listings, which look a bit like this: But for certain applications you might want to prevent this behavior and disable directory listings altogether. In this post I’m going to run through three different options for doing exactly that: Using index.html files Using middleware Using a custom filesystem…

Configuring sql.DB for better performance

There are a lot of good tutorials which talk about Go's sql.DB type and how to use it to execute SQL database queries and statements. But most of them gloss over the SetMaxOpenConns() , SetMaxIdleConns() and SetConnMaxLifetime() methods — which you can use to configure the behavior of sql.DB and alter its performance. In this post I'd like to explain exactly what these settings do and…

How to rate limit HTTP requests in Go

If you're running a HTTP server and want to rate limit user requests, the go-to package to use is probably Tollbooth by Didip Kerabat. It's well maintained, has a good range of features and a clean and clear API. But if you want something simple and lightweight – or just want to learn – it's not too difficult to roll your own middleware to handle rate limiting. In this post I'll run…

Validation snippets for Go

Over the past few years I've built up a collection of snippets for validating inputs in Go. There's nothing new or groundbreaking here, but hopefully they might save you some time. The snippets assume that the data to validate is stored as strings in r.Form , but the principles are the same no matter where the data has come from. Required inputs Blank text Min and max length (bytes) Min and max…

SCS: A session manager for Go web applications 1.7+

I’ve just released SCS , a session management package for Go 1.7+. Its design leverages Go’s new context package to automatically load and save session data via middleware. Importantly, it also provides the security features that you need when using server-side session stores (like straightforward session token regeneration) and supports both absolute and inactivity timeouts. The session data is…

Working with Redis

In this post I'm going to be looking at using Redis as a data persistence layer for a Go application. We'll start by explaining a few of the essential concepts, and then build a working web application which highlights some techniques for using Redis in a concurrency-safe way. This post assumes a basic knowledge of Redis itself (and a working installation , if you want to follow along). If you…

Organising database access in Go

A few weeks ago someone created a thread on Reddit asking: In the context of a web application what would you consider a Go best practice for accessing the database in (HTTP or other) handlers? The replies it got were a genuinely interesting mix. Some people advised using dependency injection, a few favoured the simplicity of using global variables, others suggested putting the connection pool…

Practical Persistence in Go: SQL Databases

This is the first in a series of tutorials about persisting data in Go web applications. In this post we'll be looking at SQL databases. I'll explain the basics of the database/sql package, walk through building a working application, and explore a couple of options for cleanly structuring your code. Before we get started you'll need to go get one of the drivers for the database/sql package . In…

Context-aware Handler chains

I've written a package for chaining context-aware handlers in Go, called Stack . It was heavily inspired by Alice . What do you mean by 'context-aware'? If you're using a middleware pattern to process HTTP requests in Go, you may want to share some data or context between middleware handlers and your application handlers. For example you might want to: Use some middleware to create a CRSF token,…

Making and using HTTP Middleware in Go

When you're building a web application, there's probably some shared functionality that you want to run for many (or even all) HTTP requests. You might want to log every request, gzip every response, or check that a user is authenticated before sending them any content. One way of organizing this shared functionality is to set it up as middleware — essentially a self-contained block of code…

Simple 'flash' messages in Go

Often in web applications you need to temporarily store data in-between requests, such as an error or success message during the Post-Redirect-Get process for a form submission. Frameworks such as Rails and Django have the concept of transient single-use flash messages to help with this. In this post I'm going to look at a way to create your own cookie-based flash messages in Go. We'll start by…

Form validation and processing in Go

In this post I want to outline a sensible pattern that you can use for validating and processing HTML forms in Go web applications. Over the years I've tried out a number of different approaches, but this is the basic pattern that I always keep coming back to. It's clear and uncomplicated, but also flexible and extensible enough to work well in a wide variety of projects and scenarios. To…

HTTP Response Snippets for Go

Taking inspiration from the Rails layouts and rendering guide, I thought it'd be a nice idea to build a snippet collection illustrating some common HTTP responses for Go web applications. Sending Headers Only Rendering Plain Text Rendering JSON Rendering XML Serving a File Rendering a HTML Template Rendering a HTML Template to a String Using Layouts and Nested Templates Sending Headers Only File:…

Understanding Mutexes

For anyone new to building web applications with Go, it's important to realise that all incoming HTTP requests are served in their own Goroutine. This means that any code in or called by your application handlers will be running concurrently, and there is a risk of race conditions occurring. In case you're new to concurrent programming, I'll quickly explain the problem. Race conditions occur when…