Hein Lin Zaw, home
All projects
Project 02 / 032026

Snippetbox

A server-rendered Go web app for sharing text snippets, with sessions, CSRF protection, MySQL persistence, and tests around the HTTP layer.

Year
2026
Role
Backend & HTTP fundamentals
Stack

Snippetbox is a small web application where users can sign up, log in, and share text snippets that expire after a set number of days. This project follows the structure of Alex Edwards’ Let’s Go, which I used to learn how a Go web application fits together without a framework.

The feature set is deliberately small. The learning was in the details around it.

What it does

  • Shows the ten most recent snippets on the home page.
  • Lets authenticated users create snippets with an expiry date.
  • Handles signup, login, and logout with hashed passwords.
  • Stores users and snippets in MySQL.
  • Protects state-changing requests with CSRF tokens.
  • Serves templates and static files from an embedded filesystem.

How it is put together

The application uses Go’s standard net/http package with httprouter for routes and alice for middleware chaining. Dependencies are passed explicitly into an application struct: loggers, the snippet and user models, a template cache, a form decoder, and a session manager.

Sessions are stored in MySQL through scs, with a 12-hour lifetime. Passwords are hashed with bcrypt. The middleware chain handles panic recovery, request logging, secure headers, authentication, and CSRF protection.

The UI is server-rendered with html/template. Templates are parsed once at startup into a cache, and the static assets and templates are embedded into the binary with embed.FS, so deployment is a single executable plus a database.

There are tests around the handlers, template rendering, and middleware. They are not exhaustive, but they caught several regressions while I was changing the authentication flow.

What was hard

  • Understanding the order of the middleware chain and which handlers should require authentication.
  • Getting sessions and CSRF protection to work together without breaking form submissions.
  • Learning how html/template handles nested templates and dynamic data.
  • Making database errors meaningful instead of leaking them into the HTTP response.

The biggest shift was learning to think in terms of a request passing through a chain of small wrappers, each with one job.

What I’d do next

  • Add integration tests against a real MySQL instance and a Docker Compose setup for local development.
  • Add pagination and search for snippets.
  • Add rate limiting on the login and signup endpoints.
  • Deploy it behind Nginx and write a short operational runbook.
  • Replace the text logs with structured logging and request IDs.

This project is where Go’s standard library stopped feeling like a list of packages and started feeling like a set of tools I could combine.