Verifying Cursor's Generated Requests Against the Contract
Quick answer: An AI coding assistant like Cursor will happily generate a request that looks correct in the editor but drifts from the actual API contract, because it is working from natural language and surrounding code rather than a validated schema. The reliable way to catch this is to run every generated request against the contract, linting the request definition and executing it against a mock or contract-driven harness that asserts the path, method, headers, and body shape, rather than eyeballing the code or trusting that a 200 in one happy path proves conformance. The key distinction is between a request that works once and a request that is valid, which differ as soon as you hit an error case, an optional field, or a schema change. If you treat the generated code as finished because it returns data in the common case, the drift surfaces later as a broken edge case in production, far from the prompt that produced it.
Generative editors are genuinely fast at producing fetch calls, client setup, and even retry logic, and for a developer in flow that speed is valuable. The risk is that the model's confidence is uniform across correct and incorrect details; a guessed header, a field that was renamed, or a type that should be a number but is sent as a string all appear with the same polished syntax as the correct parts. The contract is the external reference that can separate them. When the OpenAPI description is treated as the source of truth and the generated request is checked against it mechanically, the assistant becomes a fast producer of code that still has to pass the same gate as hand-written code, rather than an authority on what the API accepts.
What "works" hides versus what the contract checks
A single successful call exercises only a narrow slice, while the contract covers the full shape.
| Aspect | One happy-path 200 | Contract verification |
|---|---|---|
| Path and method | Confirmed for the call | Matched to declared routes |
| Required headers | Only those sent | Flagged if missing |
| Body field types | Accepted instance | Validated against schema |
| Optional/null fields | Not exercised | Checked for conformance |
| Error responses | Never seen | Defined and testable |
The optional and null fields row is where generated code most often fails in practice, because the model tends to emit a plausible subset and never exercises the boundary conditions that a schema explicitly allows or forbids.
Lint and run generated requests against a mock
First validate the request definition against the schema with a linter, then execute it against a contract-driven mock that returns the declared responses. This turns the check into something that can run in CI on every change rather than relying on manual review.
# validate a generated request fixture against the contract
npx @stoplight/spectral-cli lint openapi.yaml
# run the request against a contract mock and assert the shape
# generated body is checked against the request schema before sending
const result = await contractMock.send({
method: "POST",
path: "/invoices",
body: cursorGeneratedBody,
});
assert(result.status === 201);
assertValidAgainstSchema(result.body, "Invoice");
Using a mock rather than a live service keeps the test deterministic and lets you assert the error branches too, so the generated request is proven against both the success and failure responses the contract documents, not just whichever state a shared test server happens to be in.
Make the check a recurring gate, not a one-off
Generated code drifts when the contract changes, so a single verification at the time of writing goes stale. Wiring the contract check into the test suite means a renamed field or tightened constraint fails the build regardless of whether the code was originally written by a person or generated, and it removes the need to remember which files were AI-produced.
// a focused test keeps the generated caller honest
it("generated createInvoice request matches the contract", async () => {
const payload = buildCreateInvoicePayload(fixture);
const report = await validator.validateRequest("POST", "/invoices", payload);
expect(report.errors).toEqual([]);
});
Local-first tools that keep the contract and the request side by side make this loop cheap, because the validation runs against files in the repository and does not depend on a cloud service. The generated editor and the verification tool each play to their strength: the model produces code quickly, and the contract-based check decides whether that code is valid.
The practical rule is to treat every AI-generated request as unverified until it has been checked against the contract and exercised against a mock, including error and optional-field cases. A happy-path 200 is evidence of a working instance, not a valid request, and it will not catch the drift that appears on the next schema change. Put the check in CI so it runs continuously, and Cursor's speed becomes a productivity gain without quietly introducing requests that the API does not actually accept.
Frequently asked questions
Why does a generated request that returns 200 still fail review?
A 200 only proves one instance worked. The request can still miss required headers, send wrong field types, or mishandle optional and null fields that the contract defines but the happy path never touches.
How do I verify a generated request without a live server?
Lint the request against the schema and run it against a contract-driven mock, which returns the declared responses and lets you test both success and error branches deterministically.
Is one verification when the code is written enough?
No. The contract changes over time, so put the check in CI and let it run on every build, catching drift whether the code was hand-written or generated.
What is the most common generated-request defect?
Plausible-looking subsets of the body with wrong types or renamed fields, plus unexercised optional and null handling, because the model emits likely code rather than validating against the schema.
Does this require a cloud service?
No. Local-first tools validate the request against the contract files in the repository, so the gate runs offline and in CI without depending on a hosted workspace.
This is part of the Powerduck vs Cursor comparison — start there for the full picture of AI-assisted API work.