Week 16: Capstone: Build & Deploy a Production-Ready Go API

Fifteen weeks of individual pieces — types, structs and interfaces, goroutines and channels, testing, a real REST API, a real database, error handling and observability, and a deployment pipeline — come together into one project this week: a production-shaped Go service you build, test, and actually ship.

Module 16 of 16 Week 16 of 16 ~6–8 Hours Hands-on Exercise Included

By the end of this week, you'll be able to

  • Design and scope a capstone API that genuinely exercises concurrency, a real database, and observability
  • Build it with the structure, testing, and error-handling conventions from every prior week
  • Deploy it through a real, working CI/CD pipeline into a container
  • Profile and fix at least one real bottleneck before calling it done

1. The Capstone Brief

Build a real, small REST API — not a copy of the task tracker built across Weeks 10–15, something with its own genuine reason to use concurrency — that includes all of the following:

  • A database-backed resource, with migrations versioned per Week 12.
  • At least one endpoint that genuinely benefits from concurrency — fetching from multiple sources in parallel with goroutines and a sync.WaitGroup, or a background worker pool processing jobs off a channel.
  • Table-driven tests with a mocked dependency, per Week 9, covering the core logic.
  • Structured logging and at least one wrapped, inspectable error chain, per Week 13.
  • A health check, environment-based configuration, and a multi-stage Dockerfile, per Week 14.
  • A CI pipeline that builds, vets, tests (with -race), and publishes an image on every push.

A few ideas that naturally need real concurrency: a service that aggregates data from several external APIs concurrently per request; a background job processor pulling work off a queue with a worker pool; a rate-limited proxy in front of a slower upstream service.

2. Building It

Work in the order this course taught the pieces — it's also the order that avoids the most rework:

  1. Scaffold the module and project structure (Week 8) first, before writing any real logic.
  2. Define your core types and interfaces (Week 3) — especially the interface for whatever dependency you'll mock in tests.
  3. Build the database layer and migrations (Week 12) against a real local database.
  4. Build the HTTP layer — routes, middleware, validation, consistent errors (Weeks 10–11) — wiring it to the database layer.
  5. Add the concurrent piece last, once the sequential version works end to end — concurrency is much easier to add correctly to already-working code than to debug simultaneously with everything else.

3. Testing & Observability Pass

Before deploying, bring Weeks 9 and 13 to bear deliberately, not as an afterthought:

  • Table-driven tests for the core business logic, run with go test -race -cover ./... — the race flag matters more here than anywhere else in this course, given the concurrent piece you just added.
  • Every error crossing a package boundary wrapped with %w and meaningful context.
  • Structured slog logging on every request and every error path.
  • A quick pprof pass (Week 15) on whatever endpoint does the most work — fix anything the flame graph actually points to; don't invent work the profile doesn't support.

4. Containerize & Deploy

Finish with a real, working pipeline — this is the step that turns "a project on my laptop" into a portfolio piece an employer can actually see run:

  • A multi-stage Dockerfile producing a minimal image, confirmed working with docker run against a real (or containerized) database.
  • A CI workflow, from Week 14, that runs on every push and only publishes an image if the build, vet, and race-enabled test suite all pass.
  • A README documenting what the service does, why it needs concurrency, how to run it locally, and what the CI pipeline does — the kind of documentation that makes the project legible to someone (an employer, a future you) who wasn't there for the sixteen weeks that built it.

That's the full 16-week Go curriculum. Congratulations on shipping a real, production-shaped service — from go run in Week 1 to a container built, tested, and published by its own CI pipeline here in Week 16.

5. Hands-on Exercise

Hands-on

Build and ship the capstone

Design, build, test, and deploy a production-shaped Go API with a genuine concurrent component.

Requirements:

  1. A short written scope (half a page) naming the resource, the database schema, and specifically why the concurrent piece you chose genuinely needs concurrency rather than being concurrent for its own sake.
  2. A working API with database-backed CRUD, middleware (logging, recovery), consistent error responses, and request validation.
  3. At least one genuinely concurrent endpoint or background process, free of the data races and deadlocks covered in Weeks 6–7 — confirmed with go test -race.
  4. Table-driven tests covering the core logic against a mocked dependency, structured logging, and wrapped errors throughout.
  5. A working multi-stage Docker build and a CI pipeline that builds, vets, tests, and publishes an image on every push — plus a README documenting all of it.
Hint

If you're short on time, prioritize in this order: a correct, race-free concurrent feature over an elaborate one; a working CI pipeline that actually publishes an image over broader test coverage; and an honest, clear README over a longer feature list — a smaller capstone that's genuinely finished, deployed, and documented is a stronger result (and a stronger portfolio piece) than an ambitious one still half-built.

6. Knowledge Check

Four quick questions. Expand each to check your answer.

Q1

Why does the capstone specifically require an endpoint or process that "genuinely" needs concurrency, rather than concurrency added anywhere for its own sake?

Concurrency added where it isn't needed adds real complexity — the same data-race and deadlock risks from Weeks 6–7 — without a corresponding benefit, which is worse than not using it at all. Requiring a genuine use case (parallel calls to multiple external services, a background worker pool) ensures the capstone demonstrates judgment about when concurrency actually helps, not just familiarity with the syntax.

Q2

Why does the suggested build order put the concurrent piece last, after the sequential API already works end to end?

Debugging a new feature and debugging new concurrency bugs at the same time is much harder than debugging either alone — building the sequential version first means any concurrency-specific bug that shows up afterward is isolated to the one piece that just changed, rather than tangled up with routing, database, or validation bugs that could just as easily be the cause.

Q3

Why does -race matter more for the capstone specifically than it did for earlier, non-concurrent exercises in this course?

The capstone is required to include a genuinely concurrent component, which is exactly the kind of code where a data race can pass every functional test while still being a real, timing-dependent bug — Go's race detector is the one tool in this course actually capable of catching that class of bug directly, rather than relying on a test happening to trigger the race by chance.

Q4

Why does this week's brief treat the README as part of the deliverable, not an optional extra?

A working, deployed service that nobody besides its author can understand or run isn't fully legible as a portfolio piece — the README is what lets an employer, a future maintainer, or a future version of the person who built it, understand what the service does, why its concurrent design exists, and how to actually run and deploy it, without having to reverse-engineer sixteen weeks of context from the code alone.