# Generated the API contract outward from the database — OpenAPI, a 44,076‑line typed TypeScript client, 61 mock handlers and the limits the UI enforces — with a guard at every hop that fails on drift.

2025

**Situation.** Frontend and backend move at their own pace, and their assumptions about a request payload can drift apart without anyone noticing. The way you usually find out is a 422 in the browser — after the mismatch has already shipped, which is the most expensive moment to learn about it. Writing the two sides by hand from the same document does not fix it; it just moves the drift to whoever forgot to reread the document.

**Task.** The two sides had to be generated from one source rather than agreed between two, with every step of the generation checked instead of trusted.

**Action.** The chain starts at the database and runs outward. The schema and its functions define the shapes; the Go types define the API; Huma emits the OpenAPI description from those; a typed TypeScript client — 44,076 lines of it — is generated from that description; 61 mock handlers are generated alongside it so the frontend's own tests run against the real contract rather than a hand‑written fixture; and the limits the UI enforces on a form come from the same place instead of being retyped into a validator. Every hop has a guard. A contract check in CI compares what the frontend sends against what the API expects and fails the build on divergence, with a schema probe underneath it that checks the real shapes rather than a description of them. It deliberately covers where drift likes to hide: optional body fields, where "missing" and "null" get confused, and query‑parameter enums, where the two sides can quietly disagree on the allowed values.

**Result.** A field cannot change on one side only — it fails at the first hop that notices, in a build, minutes after the change. That took out a recurring and genuinely annoying class of bug, the kind invisible in code review that only shows up at runtime. The cost is a generation step in the middle of everything: regenerating is a chore, and the chain is only as trustworthy as its least‑guarded link, which is why each hop got one.

---

- Role: Backend Engineer
- Categories: [Backend Engineering](https://platform.engineer.company/categories/backend/), [APIs & Integration](https://platform.engineer.company/categories/api/), [DevOps](https://platform.engineer.company/categories/devops/), [Automation & CI/CD](https://platform.engineer.company/categories/automation/), [Reliability & Backups](https://platform.engineer.company/categories/reliability/), [Testing & QA](https://platform.engineer.company/categories/testing/)
- Services: [Backend & API Development](https://platform.engineer.company/services/backend-development/), [DevOps & CI/CD Automation](https://platform.engineer.company/services/devops-cicd/)

<https://platform.engineer.company/portfolio/built-a-request-schema-validation-contract-with-automated-61/>
