DEV Community

Cover image for A Beginner's Guide to Writing OpenAPI Specifications
Vyankatesh S Repal
Vyankatesh S Repal

Posted on

A Beginner's Guide to Writing OpenAPI Specifications

If you're new to API development, you've likely heard of OpenAPI. It's a powerful tool that helps you define, understand, and document your APIs in a standardized way. In this guide, we'll walk through the basics of creating an OpenAPI Specification (OAS) using a sample specification for Payment APIs. By the end, you'll know how to set up your own OAS and even generate code based on openAPI specification using Swagger tools.

Getting Started with OpenAPI

OpenAPI Specification (OAS) is a standard for describing RESTful APIs. It allows developers to describe the structure of their APIs so that machines can read them, making it easier to generate documentation and code for the APIs through specification. OAS are usually prepared in either YAML or JSON format. This blog illustrates an YAML example. We can convert any YANL specification using JSON and vice versa using tools like YAML to JSON converter.
To check OpenAPI map, refer to link: https://openapi-map.apihandyman.io/

Mandatory Properties in OpenAPI

Before diving into the details, it's important to understand the mandatory properties required in an OpenAPI specification:

  1. openapi: The version of the OpenAPI Specification you're using (e.g., 3.0.3).
  2. info: Metadata about the API, such as the title, description, version, and contact information.
  3. paths: The available API paths and operations.

Security Definitions

Security is a critical aspect of APIs. You can define security schemes globally or at the individual API level. Here’s how you can do it:

1. Global Security: You can define security globally using the security property at the root level. This will apply to all API operations unless overridden.

security:
-BasicAuth: []
-BearerAuth: []

2. Security Schemes in Components: Use the securitySchemes under the components object to define reusable security schemes. Components are described in further part of this blog.

components:
securitySchemes:
BasicAuth:
type: http
scheme: basic
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT

3. API-specific Security: You can also apply security to specific APIs using the security property within each path operation.

paths:
/payment/status:
get:
security:
- BearerAuth: []

Grouping APIs with Tags

Tags allow you to group related API operations, which makes your API documentation cleaner and easier to navigate. For instance, in the example below, we group our APIs into two categories: Retrieve Payments and Initiate Payments. Tags defined at the root level can be used for specific APIs.

tags:
-name: _Retrieve Payments_
description: APIs to retrieve payment details
-name: Initiate Payments
description: APIs to initiate new credit transfers

Using defined tag for specific API:

paths:
/payment/status:
get:
operationId: getAllPaymentsStatus
_tags:
- Retrieve Payments_

Defining Methods, Requests, and Responses

In OpenAPI, each path can have multiple methods, such as GET, POST, PUT, etc. Each method can define its own request body, parameters, and responses. You can also use the operationId to uniquely identify an operation, which is useful when generating code.

paths:
/payment/status:
get:
operationId: getAllPaymentsStatus
tags:
- Retrieve Payments
summary: Retrieve all payments
description: Returns the list of payments initiated with their status
responses:
'200':
description: Returns the list of payments
content:
application/json:
schema:
type: array
items:
type: object
properties:
paymentId:
type: integer
paymentStatus:
type: string
examples:
example:
value:
- paymentId: 101
paymentStatus: ACSC

Using Components for Reusability

The components section in OpenAPI allows you to define reusable parameters, request bodies, responses, and schemas. This is especially useful when you have common elements across multiple APIs.

components:
schemas:
paymentDetailsSchema:
type: object
properties:
paymentId:
type: number
amount:
type: number
format: float
currency:
type: string
creationDate:
type: string
format: date-time
required:
- paymentId
- amount
- currency
- creationDate

This schema can then be referenced in multiple places within the API.

Inheritance and Polymorphism

OpenAPI supports inheritance using the allOf keyword and polymorphism with oneOf and anyOf. This allows you to create complex data structures that share common properties.

For example, a schema with polymorphism:
components:
schemas:
accountDetails:
oneOf:
- $ref: '#/components/schemas/bankTransferDetailsSchema'
- $ref: '#/components/schemas/walletTransferDetailsSchema'

Linking APIs

When one API's output can be used as another API's input, you can define links in the OpenAPI Specification. This is useful for creating more dynamic and interconnected API workflows.

components:
links:
LinkName_GetSinglePaymentStatus:
operationId: getSinglePaymentStatus
parameters:
paymentId: $response.body#/paymentId

Generating Code from OpenAPI Specification

One of the powerful features of OpenAPI is the ability to generate code automatically. Using tools like Swagger, you can generate both client and server code using options "Generate Server" or "Generate Client" available on https://editor.swagger.io/

Code-First Approach

In addition to writing the OpenAPI specification first, you can also take a "code-first" approach. In this method, you start by coding your APIs and then use tools to generate the OpenAPI specification based on your code. This approach can be beneficial if you prefer to focus on coding and let the documentation follow.

Conclusion

OpenAPI Specification is a powerful tool in your API development toolkit. Whether you take a specification-first or code-first approach, OpenAPI helps ensure your APIs are well-documented, consistent, and easy to integrate.

For more information and to see a sample project, check out the GitHub repository.

If you have any questions or thoughts, please drop a comment below. I’d love to hear your feedback.

Top comments (0)