I rewrote the back end of my Taigen note taking app to use Go instead of Python. Go piqued my curiousity when I found its standard library has everything to build a web app (routing, templates, SQL, even a production-quality web server). And its design team included Ken Thompson, creator of Unix. Hmmm…
So I learned Go while hammering out a new back end and the result is a single binary that’s fast and light on memory and doesn’t need a web framework, virtual environment, or third party web server. Even the app’s static assets (image files, CSS, and Javascript) are embedded in the binary.
Go has everything you need to build web components and nothing you don’t. Fewer moving parts means greater reliability.
The most reliable components are the ones you leave out.
Gordon BellIn anything at all, perfection is finally attained not when there is no longer anything to add, but when there is no longer anything to take away, when a body has been stripped down to its nakedness.
Antoine de Saint-Exupéry, Wind, Sand, and Stars
ORM vs SQL
You can find third party ORM modules for Go but it’s easier and faster to just write raw SQL. When I use an ORM I write the query in SQL first anyway so I may as well skip the extra step. Go’s SQL module is easy to learn and use, and the official docs give you all the information you need.
Common Table Expression (CTE)
WITH provides a way to write subqueries for use in a larger SELECT query. The subqueries, which are often referred to as Common Table Expressions or CTEs, can be thought of as defining temporary tables that exist just for this query. One use of this feature is to break down complicated queries into simpler parts.
PostgreSQL docs
I used a CTE for my weather station daily report. One SQL string calculates the daily min and max values for temperature, pressure, humidity, and internal temperature, and adds it to a daily report column. Imagine trying to do this with an ORM:
INSERT INTO dailyreports (date, max_temp, min_temp, max_pressure, min_pressure, max_humidity, min_humidity, max_internal_temp, min_internal_temp, user_id)
SELECT $4, MAX(temp), MIN(temp), MAX(pressure), MIN(pressure), MAX(humidity), MIN(humidity), MAX(internal_temp), MIN(internal_temp), $1 FROM snapshots WHERE user_id = $1 AND $2 <= timestamp AND timestamp <= $3
Session handling
The Go standard library doesn’t have a session handler so you have to use a third party library or write your own. Session handlers are pretty simple to write. All you need are:
- A sessions table with columns for session ID, expiration date, and user ID.
- A function to set the cookie with the session ID.
- A middleware1 that checks incoming requests for a cookie with a valid session ID, redirecting them to
/login/
if they don’t have one.
That’s it. If you know how to use sessions, cookies, and the like safely you probably know enough to write a session handler. And OWASP has a session management cheat sheet to fill in the details.
-
Middleware acts as a middleman between the client and your app. The middleware wraps around the app, allowing it to modify a request before your app receives it or modify a response after your app processes it. An app can have several middleware, all wrapped around the app like the layers of an onion. ↩