Day 110 — Project: OpenAPI Docs¶
Month 4 · Week 4 · ⬅ Day 109 · Day 111 ➡ · Journal index
🎯 Learning Objective¶
Describe the capstone API with an OpenAPI 3.0 document and serve interactive docs, so the API has a machine-readable contract clients and tools can consume.
📚 Topics¶
- OpenAPI 3.0 object model:
info,paths, operations,components/schemas,$ref - Generating the spec from code (swaggo) vs hand-writing YAML/JSON
- Serving
/openapi.jsonand rendering it with swagger-ui / Redoc - Contract-first vs code-first API design
📖 Reading / Sources¶
- OpenAPI 3.0 Specification
- swaggo/swag — generate Swagger from Go annotations
- Swagger UI · Redoc
- Learn OpenAPI (Swagger docs)
📝 Notes¶
- An OpenAPI document is the machine-readable contract for a REST API: endpoints, methods, request/response schemas, status codes. It's just structured JSON/YAML → [[openapi]].
- Core objects:
info(title/version),paths(a map of URL → method → operation), each operation hasresponseskeyed by status code, and reusablecomponents/schemasreferenced via$ref: '#/components/schemas/User'to avoid repetition → [[dry]]. - Two workflows: code-first generates the spec from annotations/structs (swaggo) so docs can't drift from handlers; contract-first writes the spec first and generates server/client stubs from it. Both are valid; code-first is easiest to keep in sync on a small project.
- Pin the
versionininfoto your release (e.g.0.4.0) so consumers know which contract they're reading. - Serving docs: expose
/openapi.jsonand point a static swagger-ui or Redoc bundle at that URL; the UI fetches the JSON and renders an interactive explorer. Nothing Go-specific is required to render it. - Because the document is just JSON, you can model it as Go structs and
json.MarshalIndentit —encoding/jsonsorts map keys, so the output is deterministic (good for committing/diffing) → [[encoding-json]]. - Keep the spec in version control and assert key invariants in a test (every route documented, operationIds unique) so docs are part of the build, not an afterthought.
💻 Code Examples¶
// Code-first with swaggo: annotations on the handler generate the spec.
// @Summary Create a user
// @Accept json
// @Produce json
// @Param user body CreateUserRequest true "new user"
// @Success 201 {object} User
// @Failure 409 {object} ErrorResponse
// @Router /users [post]
func (h *Handler) create(w http.ResponseWriter, r *http.Request) { /* ... */ }
Stdlib version — build the OpenAPI document as structs and serve
/openapi.json+ a docs page:examples/month-04/openapi/main.go· Run:go run ./examples/month-04/openapi
🏋️ Exercises / Practice¶
| Exercise | Status | Link |
|---|---|---|
| Build a valid OpenAPI 3.0 doc from routes (deterministic JSON) | ✅ | exercises/month-04/week-4/openapi |
| Serve /openapi.json + /docs | ✅ | examples/month-04/openapi |
🐛 Mistakes Made¶
- Hand-wrote response schemas inline for every endpoint; refactored to a shared
components/schemas/Userreferenced with$refto stop duplication. - Generated spec drifted from the handlers after a field rename; added a test asserting the documented fields match the struct tags so it can't silently rot.
❓ Open Questions¶
- Worth adopting contract-first (write the YAML, generate handlers) for the next project, or stick with swaggo code-first? Depends on whether multiple teams consume the API.
🧠 Active Recall (answer without looking)¶
- Q: What does
$ref: '#/components/schemas/User'accomplish in an OpenAPI doc?
A
It references a schema defined once under `components/schemas`, so the `User` shape is declared in one place and reused across many operations — DRY for the contract.- Q: Why does marshalling the spec with
encoding/jsongive deterministic output?
A
`encoding/json` marshals map keys in sorted order, so the same set of paths/schemas always serialises identically — making the committed `openapi.json` diff cleanly.🪶 Feynman Reflection¶
An OpenAPI file is the menu of a restaurant written in a language every delivery app understands: what dishes (endpoints) exist, what you must order with (request body), and what you'll get back (response schema + status). swagger-ui is the glossy photo menu generated from that text. Generating the menu from the kitchen's actual recipes (code-first) means the photos can't lie about what's served.
🕳️ Knowledge Gaps¶
- Documenting auth schemes (
securitySchemes, bearer JWT) and error envelopes consistently across endpoints — flesh out next.
✅ Summary¶
I can describe the API as a versioned OpenAPI 3.0 document, reuse schemas with $ref, serve /openapi.json for swagger-ui/Redoc, and keep the spec honest with a test.
⏭️ Next Steps / Prep for Tomorrow¶
- Day 111: containerise the service with a multi-stage Dockerfile and wire up CI.
| Time spent | Difficulty | Confidence |
|---|---|---|
| 90 min | 🟦🟦⬜⬜⬜ | 🟦🟦🟦⬜⬜ |
Suggested commit: docs(project): OpenAPI 3.0 spec + served docs (day 110)