↓ Skip to main content

API OpenAPI Dev

Plan Your API Before You Build It: An OpenAPI-First Workflow

The OpenAPI planning workflow we adopted so frontend and backend agree on the contract before the sprint starts, with an example YAML.

Plan Your API Before You Build It: An OpenAPI-First Workflow

I wrote recently about OpenAPI-first development in general terms. This is the concrete version: the planning workflow we’re trialling on my team, and the example YAML that goes with it.

Where this came from
#

The push came from our retro. The feedback was blunt about how little visibility anyone had into API planning: backend built endpoints against their own reading of the requirements, frontend discovered the response shapes after the fact, and the gaps surfaced at integration time — the most expensive possible moment. The proposal was to pull both sides into the planning phase and make the OpenAPI schema the thing everything hangs off.

The process
#

Each week we pick two representatives, one backend and one frontend. Their job is to understand the sprint’s requirements and get the planning OpenAPI schema to match. They review the schema together, revise whatever doesn’t line up, and by the end both sides know exactly what’s being built — before anyone builds it.

Once the revisions settle, the schema gets committed to the repo, and CI/CD generates a mock API from the yaml. When the sprint wraps up, a fresh yaml is cut covering the next sprint’s API requirements, and the cycle repeats.

Tooling notes
#

  • For visualising the yaml, Swagger Editor does the job: upload the file and see it rendered as a proper Swagger document.
  • This schema is a planning artefact only. Once the real API is deployed, the service should generate its own openapi.json, which you can download and feed back into the next round of planning.
  • The CI/CD pipeline needs to accept a yaml and stand up a mock server from it. openapi-mock looks like a solid option for that.

Why bother
#

Because the arguments move to the cheapest possible place. With a frontend and a backend engineer in the room while the schema is written, misunderstandings get caught before they become code. The API requirements are agreed once instead of renegotiated mid-sprint, the mock server means frontend starts immediately rather than waiting, and far fewer critical details slip through — they’d have to get past two pairs of eyes and a written contract.

None of this is revolutionary. It’s just planning made concrete enough that a machine can serve it back to you as a mock — which, it turns out, is about the level of concrete a plan needs to be.

Appendix A - yaml example
#

openapi: 3.1.0
info:
  title: MyApp Sprint 3
  description: Planning schema for sprint 3. Drives the mock server only.
  version: 0.3.0
servers:
  - url: https://api-mock.example.com/v1
tags:
  - name: lists
    description: Saved lists feature (PROJ-123)
security:
  - api_key: []
paths:
  /lists:
    get:
      tags: [lists]
      summary: Return the current user's saved lists
      operationId: getLists
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/List'
  /lists/{listId}:
    get:
      tags: [lists]
      summary: Find a list by ID
      operationId: getListById
      parameters:
        - name: listId
          in: path
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/List'
        '404':
          description: List not found
components:
  schemas:
    List:
      type: object
      required: [id, title]
      properties:
        id:
          type: integer
          format: int64
          examples: [10]
        title:
          type: string
          examples: [Weekend reading]
        itemCount:
          type: integer
          examples: [7]
  securitySchemes:
    api_key:
      type: apiKey
      name: X-API-Key
      in: header