How does OpenAPI support asynchronous APIs?

How does OpenAPI support asynchronous APIs? #

The rise of asynchronous communication has become one of the key trends in modern software engineering. As opposed to synchronous communication where a request and response happen in a sequential manner, asynchronous APIs allow for more flexible and resilient communication patterns. OpenAPI Specification (OAS) is the cornerstone framework for defining synchronous RESTful APIs, but as the need for asynchronous APIs rises, developers and engineers might wonder how OpenAPI supports this new paradigm.

This article explores how OpenAPI supports asynchronous APIs, how to define asynchronous endpoints, and introduces related technologies like AsyncAPI, which is specifically designed for asynchronous APIs.

Understanding Asynchronous APIs #

Before diving into the specifics of OpenAPI, it’s essential to have a clear understanding of what asynchronous APIs are. In contrast to synchronous APIs where the client sends a request and waits for an immediate response from the server, asynchronous APIs operate on the principle of non-blocking communication:

  • Event-Driven: Asynchronous APIs are usually event-driven. An event triggers a message that gets sent to a message broker or a service, which can then process the message at its own speed.
  • Non-Blocking: The caller does not wait for the completion of the task, allowing for other tasks to be performed in the meantime.
  • Suitable for Real-time Communication: Widely used in web sockets, IoT, and microservices architecture where real-time or near-real-time processing is crucial.

Defining Asynchronous APIs with OpenAPI #

The OpenAPI Specification (OAS) primarily caters to RESTful APIs, which are fundamentally synchronous. However, it does have provisions to accommodate asynchronous operations:

Callbacks #

Callbacks are one of the features in OpenAPI 3.0 that enable defining asynchronous interactions. A callback is essentially a way to define a post-processing operation that a server will call back to once it has finished processing the request.

Here’s an example OpenAPI definition for a callback:

paths:
  /createResource:
    post:
      summary: "Create a resource"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Resource"
      responses:
        '201':
          description: "Resource created"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Resource"
      callbacks:
        onSuccess:
          "{$request.body#/callbackUrl}":
            post:
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      $ref: "#/components/schemas/OperationStatus"
              responses:
                '200':
                  description: "Callback received"

In this example, the server will communicate back to the URL specified in the callbackUrl, invoking the defined callback endpoint once it has finished processing the creation of the resource.

Webhooks #

While not explicitly part of OpenAPI, webhooks achieve asynchronous processing. OpenAPI 3.1, the latest version of OAS, provides support that aligns closely with webhooks. In simple terms, webhooks are HTTP callbacks that occur when an event happens.

Here’s an example to describe an API that supports webhooks:

components:
  schemas:
    Order:
      type: object
      properties:
        id:
          type: string
        item:
          type: string
        status:
          type: string
  
paths:
  /orders:
    post:
      summary: "Create a new order"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Order"
      responses:
        '202':
          description: "Order accepted"

webhooks:
  orderStatus:
    summary: "Status of an order"
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Order"
      responses:
        '200':
          description: "Webhook received successfully"

In this example, the endpoint /orders can notify a webhook orderStatus, giving a clear mechanism for how asynchronous updates can be disseminated to interested parties.

AsyncAPI: A Complementary Specification #

While OpenAPI provides some mechanisms for asynchronous APIs, its design primarily focuses on synchronous RESTful interactions. This is where AsyncAPI comes into play. AsyncAPI is a specification for defining asynchronous APIs and is aligned similarly to OpenAPI but specializes in non-blocking, event-driven architectures.

Key Features of AsyncAPI #

  1. Event-Driven Architecture: Supports event-driven systems natively, capturing the specific requirements and nuances of asynchronous communication.
  2. Producers and Consumers: Clearly defines both producers (services generating events) and consumers (services reacting to events).
  3. Support for Multiple Protocols: Can work with various protocols like MQTT, AMQP, WebSockets, Kafka, and more.

Example AsyncAPI Definition #

To highlight the contrast, here’s an example AsyncAPI definition for a real-time chat application:

asyncapi: 2.0.0
info:
  title: Chat API
  version: '1.0.0'
servers:
  production:
    url: 'chat.example.com:443'
    protocol: wss
channels:
  user/signedup:
    description: Channel for new user signups
    publish:
      summary: "New user has signed up"
      message:
        contentType: application/json
        payload:
          type: object
          properties:
            userId:
              type: string
              description: "ID of the new user"
  message/sent:
    description: Channel for sent messages
    subscribe:
      summary: "Subscribe to sent messages"
      message:
        contentType: application/json
        payload:
          type: object
          properties:
            messageId:
              type: string
            sender:
              type: string
            content:
              type: string

In this specification:

  • The channels are akin to what paths are in OpenAPI.
  • Each channel represents a topic or stream of events.
  • The publish and subscribe operations reflect the nature of asynchronous communication.

Integrating OpenAPI and AsyncAPI #

Many modern architectures aren’t exclusively synchronous or asynchronous; rather, they entail a blend of both. It’s feasible and often necessary to integrate both OpenAPI and AsyncAPI specifications to describe the different parts of your API comprehensively.

Combined Usage Example #

Let’s consider an e-commerce platform that uses a combination of synchronous for order placement and asynchronous for order notifications.

OpenAPI Part: #

paths:
  /order:
    post:
      summary: "Place a new order"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Order"
      responses:
        '201':
          description: "Order placed successfully"
components:
  schemas:
    Order:
      type: object
      properties:
        id:
          type: string
        item:
          type: string
        quantity:
          type: integer
          format: int32
          description: "Number of items ordered"
        price:
          type: number
          format: float
          description: "Price of the order"

AsyncAPI Part: #

asyncapi: 2.0.0
info:
  title: Order Notification API
  version: '1.0.0'
servers:
  production:
    url: 'orders.example.com:443'
    protocol: wss
channels:
  order/created:
    description: Channel for order creation notifications
    publish:
      summary: "Notify when an order is created"
      message:
        contentType: application/json
        payload:
          type: object
          properties:
            orderId:
              type: string
            status:
              type: string
              enum: [created, confirmed, shipped]

In this scenario:

  • OpenAPI defines the synchronous part (/order endpoint) where clients place orders.
  • AsyncAPI defines the asynchronous part (order/created channel) where clients can receive real-time notifications.

Conclusion #

OpenAPI does support asynchronous APIs to some extent, specifically through features like callbacks and webhooks. However, for complete, robust, and detailed specifications dedicated to asynchronous communication, AsyncAPI serves as a specialized and complementary tool. By integrating both OpenAPI and AsyncAPI, developers can harness the best of both worlds, ensuring that their applications are well-equipped to handle a blend of synchronous and asynchronous communication.

For more information, you can visit OpenAPI and AsyncAPI. Both these frameworks continually evolve, reflecting modern API design needs and practices. Adopting OpenAPI and AsyncAPI as part of your API strategy will not only enhance your system’s flexibility but also future-proof your architecture for evolving tech trends.

This website is not affiliated with the OpenAPI Initiative.