Every backend developer I know maintains two things that describe the same API.The first is the OpenAPI spec. It documents your endpoints, defines your request/response schemas, and is the thing you point new engineers to when they ask "how does this work?" It lives in the repo. It goes through code review. It's the official source of truth.The second is a Postman collection. Or a Bruno workspace. Or a folder of .http files. Or Jest/supertest tests. It's the thing you actually use to validate that the API works. It also lives somewhere. Sometimes in the repo. Sometimes in someone's Dropbox. Sometimes it doesn't exist at all because the last engineer who had it left six months ago.Here's the problem: they drift.You ship a new endpoint. You update the spec. You forget to update the test collection. Three weeks later a new engineer runs the tests and gets confused because the tests are hitting an endpoint that doesn't exist anymore.Or you change a response field, rename user_id to userId and you update the tests because the tests broke, but you forget to update the spec because the spec doesn't break, it just silently lies.This is the double-maintenance problem, and I've been annoyed by it long enough that I built something to solve it.The idea: make the spec executableOpenAPI 3.x supports custom extensions any field that starts with x- is valid and ignored by standard tooling. VolcAPI uses a v-functional-test extension to let you attach test scenarios directly to your endpoint definitions:paths: /auth/login: post: summary: User login responses: '200': description: Success v-functional-test: scenarios: ["valid_login", "wrong_password"]Then you define what those scenarios look like at the root of the same file:scenarios: valid_login: headers: Content-Type: application/json request: email: user@example.com password: password123 response: status: 200 body: contains: ["token", "user"] wrong_password: request: email: user@example.com password: wrong response: status: 401And you run it:volcapi run volcapi_local.yml -o openapi.ymlThat's the whole model. Your spec is your documentation. Your spec is your tests. One file, one update, one source of truth.Why Go?Most API testing tooling is JavaScript (Postman, Bruno, Newman, Hoppscotch) or Python (HTTPie, Schemathesis, Dredd). There's nothing wrong with those languages, but they create friction in CI:You need Node or Python in your CI environmentYou're pulling in a runtime and package dependenciesCold start time adds up when you're running tests on every PRVolcAPI compiles to a single static binary. In CI, you download the binary and run it. No setup step. This is the same reason K6 (also Go) became popular for performance testing, the distribution model just works.What it looks like in CI (goal state)The JUnit XML output is still in progress, but this is what the GitHub Actions workflow will look like once it lands:- name: Run API contract tests run: volcapi run volcapi_staging.yml -o openapi.yml env: STAGING_TOKEN: ${{ secrets.STAGING_TOKEN }}Pass/fail in the PR. No Postman Cloud subscription. No external service. The spec and the test config live in your repo and run wherever your CI runs.Where it is right nowThis is an early alpha. GET, POST, PUT, and DELETE requests work. Response validation works (status codes, JSON matching, field existence checks). Environment configs work so you can point at different hosts for local/staging/production.JUnit XML output and a working GitHub Actions example are the next things I'm building. After that: better schema validation, contract diffing, gRPC support.The repo is at https://github.com/aliamerj/volcapi. It's early. If the problem resonates, a star or a watch helps signal that it's worth continuing.What I actually want to knowIs the "spec as test suite" model something that clicks for you, or does it feel wrong? Some people feel strongly that tests should live separately from API definitions. I understand the argument, separation of concerns, different audiences for docs vs tests. But I keep coming back to the fact that they describe the same thing and should always agree with each other. If they're in the same file, they can't drift.I'd genuinely like to hear what backend developers think about this. Drop a comment.\\