DEV Community

Mean for APIKumo

Posted on

Spec-First API Development: Make Your OpenAPI File the Source of Truth

Spec-First API Development: Make Your OpenAPI File the Source of Truth

Most teams write the API first and the spec later — if ever. The code ships, the OpenAPI document drifts, and six months on the docs describe an API that no longer exists. Spec-first flips the order: you design the contract in OpenAPI before writing a single route, then generate mocks, validation, docs, and clients from that one file. The spec stops being documentation and becomes the source of truth.

Here's how to actually do it.

1. Design the contract first

Start with a minimal but precise OpenAPI 3.1 document. Describe the shape of requests and responses, not the implementation.

# openapi.yaml
openapi: 3.1.0
info:
  title: Orders API
  version: 1.0.0
paths:
  /orders/{id}:
    get:
      operationId: getOrder
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: The order
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Order" }
        "404":
          description: Not found
components:
  schemas:
    Order:
      type: object
      required: [id, status, total]
      properties:
        id: { type: string }
        status: { type: string, enum: [pending, paid, shipped] }
        total: { type: number }
Enter fullscreen mode Exit fullscreen mode

Because this is written before the code, frontend and backend can agree on the contract on day one instead of arguing about field names in code review.

2. Mock the API before it exists

Your frontend team shouldn't wait for the backend. Point a mock server at the spec and they can build against realistic responses immediately. Prism does this with zero code:

npx @stoplight/prism-cli mock openapi.yaml
# GET http://127.0.0.1:4010/orders/123
# → { "id": "string", "status": "pending", "total": 0 }
Enter fullscreen mode Exit fullscreen mode

Prism validates incoming requests against the spec and returns spec-compliant responses. If the frontend sends a malformed request, it fails against the mock — long before it ever hits real infrastructure.

3. Enforce the contract at runtime

The biggest risk with spec-first is drift: the code quietly diverges from the document. Stop that by validating live traffic against the spec. With Express:

const express = require("express");
const OpenApiValidator = require("express-openapi-validator");

const app = express();
app.use(express.json());

app.use(
  OpenApiValidator.middleware({
    apiSpec: "./openapi.yaml",
    validateRequests: true,
    validateResponses: true, // catches drift in YOUR responses too
  })
);

app.get("/orders/:id", (req, res) => {
  res.json({ id: req.params.id, status: "paid", total: 42.0 });
});

// Spec violations become clean 400/500s instead of silent bugs
app.use((err, req, res, next) => {
  res.status(err.status || 500).json({ message: err.message });
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

validateResponses: true is the part most people skip — and it's the part that matters. It fails loudly in tests when your handler returns a field the spec doesn't allow, so the code can never silently outrun the contract.

4. Generate clients instead of hand-writing them

Once the spec is authoritative, typed clients are a build step, not a chore:

npx openapi-typescript openapi.yaml -o src/api-types.ts
Enter fullscreen mode Exit fullscreen mode

Now your frontend gets compile-time errors the moment a response shape changes in the spec. No more guessing whether total is a string or a number.

Why this order matters

Spec-first works because every artifact flows from one file: mocks for parallel work, runtime validation to prevent drift, generated types for safety, and always-accurate docs. Change the spec, regenerate everything, and your whole stack stays in sync.

The friction is usually tooling sprawl — a mock server here, a validator there, a docs generator somewhere else, all pointed at copies of a spec that slowly diverge. APIKumo keeps the spec, live versioned docs, mock environments, and generated client code in one workspace, so the contract you design is the contract your team builds against. Define it once, and let everything else follow.

Top comments (0)