Skip to main content
  1. Posts/

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

· loading · loading ·
Jared Lynskey
Author
Jared Lynskey
Emerging leader and software engineer based in Seoul, South Korea

Introduction
#

Frontend and backend teams working in sequence—backend builds the API, then frontend integrates it—is slow. This post describes how we changed that by defining the API contract upfront with OpenAPI, so both teams can work in parallel.

Background and Motivation
#

The Retrospec feedback highlighted a significant gap in the visibility and planning of APIs. With rapid technological advancements, there’s an increased need for dynamic and adaptable systems. The proposed method will incorporate both backend and frontend engineers in the planning phase, aiming to ensure clarity and alignment from the get-go.

The Proposed Process
#

1. Selection of Representatives:
#

Each week, one backend and one frontend engineer will be chosen. These representatives will take the responsibility of understanding the sprint’s requirements and aligning them with the current planning OpenAPI schema.

2. Review and Revision:
#

The selected engineers will collaboratively review the OpenAPI configuration. They will ensure it aligns with the requirements and make revisions where necessary. This collaboration ensures that both sides have a clear understanding of what needs to be achieved.

3. Commitment and Generation:
#

After revisions, the changes to the OpenAPI configuration will be committed to the respective repository. Following this, the CI/CD will generate the mock-API using the provided yaml.

4. Sprint Completion:
#

Upon completion of a sprint, a new yaml will be generated. This yaml will encapsulate the next sprint’s API requirements.

Tools and Management:
#

  • Visualization of YAML: An online tool, found at Swagger Editor, can be utilized to upload and visualize the yaml as a Swagger document.

  • OpenAPI Document Management: It’s essential to understand that this proposed process is purely for the planning stage. Once the API is deployed, the respective service should generate its openapi.json. This JSON can then be downloaded and reused for further planning.

  • CI/CD Role: The CI/CD pipeline will play a pivotal role. It should be designed to accept a yaml file and deploy a mock server based on the specifications. A tool like openapi-mock can be considered for this purpose.

Why This Process is Beneficial:
#

  1. Enhanced Communication: By including both backend and frontend engineers in the planning process, there’s a direct line of communication established. This minimizes misunderstandings and ambiguities, resulting in a more streamlined development process.

  2. Improved Alignment: Both teams can have a clear understanding and agreement on the API requirements and functionalities. This means less back-and-forth during the development phase.

  3. Efficiency: With a mock server deployed based on specifications, developers can begin their work without delays, leading to faster product releases.

  4. Quality Assurance: When both backend and frontend developers are involved from the beginning, the chances of overlooking critical requirements diminish. This results in a more robust and well-functioning final product.

Conclusion
#

Define the API contract first with OpenAPI, generate a mock server, and let both teams work in parallel. The upfront planning time pays for itself in fewer integration surprises and faster delivery.

Appendix A - yaml example
#

openapi: 3.1.0
info:
  title: PKY Sprint 3
  description: |-
    PKY Sprint 3 Development Schema
  termsOfService:
  contact:
    email: jared@lynskey.co.nz
  license:
    name: None
    url: 
  version: 1.0.11
externalDocs:
  description:
  url: 
servers:
  - url: https://api-mock.com/api/v3
tags:
  - name: curation
    description: PKY-1081 Curated Lists Feature
    externalDocs:
      description: Jira Epic
      url: https://pickydev.atlassian.net/browse/PKY-1081
paths:
  /curations:
    get:
      tags:
        - curation
      summary: Return the curations created by users
      description: Returns a map of status codes to quantities
      operationId: getCurations
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: integer
                  format: int32
      security:
        - api_key: []
  /curations/{curationId}:
    get:
      tags:
        - curation
      summary: Find purchase order by ID
      description: For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.
      operationId: getOrderById
      parameters:
        - name: orderId
          in: path
          description: ID of order that needs to be fetched
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
            application/xml:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
          description: Invalid ID supplied
        '404':
          description: Order not found
    delete:
      tags:
        - curation
      summary: Delete purchase order by ID
      description: For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
      operationId: deleteOrder
      parameters:
        - name: orderId
          in: path
          description: ID of the order that needs to be deleted
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '400':
          description: Invalid ID supplied
        '404':
          description: Order not found
components:
  schemas:
    Curation:
      type: object
      properties:
        id:
          type: integer
          format: int64
          examples: [10]
        curationId:
          type: integer
          format: int64
          examples: [198772]
        quantity:
          type: integer
          format: int32
          examples: [7]
        status:
          type: string
          description: Order Status
          examples: [approved]
          enum:
            - placed
            - approved
            - delivered
        complete:
          type: boolean
      xml:
        name: order
    ApiResponse:
      type: object
      properties:
        code:
          type: integer
          format: int32
        type:
          type: string
        message:
          type: string
      xml:
        name: '##default'
  requestBodies:
    Curation:
      description: Curation object that needs to be added
      content:
        application/json:
          schema:
            $ref: 
        application/xml:
          schema:
            $ref:
  securitySchemes:
    petstore_auth:
      type: oauth2
      flows:
        implicit:
          authorizationUrl:
          scopes:
            write:curations: modify curations in your account
            read:curations: read your curations
    api_key:
      type: apiKey
      name: api_key
      in: header