question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal for Swagger Async Responses and WebHooks

See original GitHub issue

Swagger Asynchronous Reponses and WebHooks

Background

This document provides an outline of the proposed swagger format for documenting a webhook subscription and callback interface.

Background

Many SaaS systems provide some kind of event interface as core to their behaviour. There are many approaches to implementing this. No single approach is as prevalent as JSON/HTTP APIs have become for service implementation however webhooks is significtly more common than any other single approach.

This document concentrates on extending Swagger to cope with the WebHooks pattern.

WebHooks

Webhooks are a convention of use of normal Web interfaces, typically using JSON/HTTP, in which an event subscriber can register a callback URL with an event publisher. When an event occurs, the event publisher invokes an HTTP method on that URL (Typically POST) to send the information related to the event.

WebHooks in real life

Webhooks are not standardized nor formally specified, but are in common use in a substiantial number of systems.

The lack of standardisation means that there is variation in each of the following areas;

  • Whether or not a subscription API is made available - many systems instead require registration via an administrative UI
  • If a subscription API is available, its precise form varies between different systems
  • Some systems effectively require a different callback URL to be registered for each event stream, while others support subscription to multiple event streams with a single callback URL

The following conventions are commonly observed;

  • When an event occurs, where the publisher supports subscription to multiple different event streams on the same URL it is common for them to provide a parameter, or a data field within a parameter, as part of the POSTed message that specifies which event has occurred.
  • When an event occurs, almost all systems support the use of HTTP POST to convey the event information. Some mandate the use of HTTP POST, while others allow other HTTP methods to be selected as an option

Objective of the proposal

This objective of this proposal is to allow the subscription and event publication interactions involved in the WebHooks convention to be minimally modeled via Swagger, such that a Swagger-enabled SDK could;

  • Understand event structures: Provide an abstraction of each event that could occur once subcription has occurred, reducing the amount of code that a programmer has to author to process the events.
  • Discriminate between events: discriminate between events of different types that may occur so that the appropriate program logic can be invoked
  • Subcription/Publication association: (by allowing the event set+discriminator to be associated with a subscription API) allow a programmer to discover the events that can occur once they have registered
  • Documentation: extend the documentation benefits of swagger to events.

Not covered by the proposal

This proposal does not cover abstraction of the variation encountered in different implementations of the subscription API such that an SDK could standardize this phase.

Specific Proposal

x-async-responses

New tags: x-async-responses is array of event definitions. Each event definition contains the following elements;

  • event-id: a logical name for the event stream
  • description: a text description of the event stream
  • parameters
    • This allows the signature of the HTTP POST performed when an event occurs in the source system to be modelled
    • With the exception of eventDiscriminator it is identical to a normal Swagger parameter definition
    • In the webhooks convention, the event payload is contained on the body of the HTTP method invoked
  • eventDiscriminator:
    • Parameter: parameterName
    • This introduced to cope with cases where the webhooks callback URL can receive more than one type of event and the event type is conveyed in the header or query perameters. In these cases, the polymorphic Swagger discriminator cannot be used. The Parameter field specifies which parameter is used to discriminate between different events that may occur.
    • If eventDiscriminator is present, then the parameter named has a value equal to the event-id when that event occurs
    • If eventDiscriminator is absent, then event types are discriminated using the Swagger discriminator, as specified for the schema of the body parameter
  • Usage in the context of a subscription API
    • If x-async-responses is included or referred to as an element within an operation definition, as shown in this example, this is an indication that the events defined may occur as a result of invoking that operation.
  • Usage standalone
    • If x-async-responses appears at the top level, this indicates that the subscription happens via some unspecified mechanism.
    • It is common for systems that support WebHooks to provide a UI that allows the subscription to be performed, for example

Discriminator in a header: Swagger YAML snippet

We have chosen to illustrate example using github because it has a subcription API.

Please refer to the Github documentation on ‘create a hook’ for further information on the API definition provided by Github for webhooks.

Please note that all elements beginning with x-github or x-hub are part of the Github API specification, and do not form part of this proposal. Finally, the Swagger below is not comprehensive - for example, not all objects are fully modeled.

paths:
  /repos/owner/repo/hooks:
    post:
      operationId: 'CreateHook'
      summary: Create a webhook in GITHUB
      description: |
        Call this API to create a new WebHook in Github
      parameters:
        - name: subscription
          in: body
          description: Details to subscribe for a callback on a given set of events
          required: true
          schema:
            $ref: '#/definitions/Subscription'
      tags:
        - Webhook
      responses:
        '202':
          description: Details of the subscription created to the webhook
          schema:
            $ref: '#/definitions/SubscriptionResponse'
      x-async-responses:
        - eventId: commentStream
          description: Comment event stream
          eventDiscriminator:
            parameter: X-GitHub-Event
          parameters:
            - name: comment
              in: body
              required: true
              schema:
                $ref: '#/definitions/comment'
            - name: X-GitHub-Event
              in: header
              type: string
            - name: X-GitHub-Delivery
              in: header
              type: string
            - name: X-Hub-Signature
              in: header
              type: string
        - event-id: deployment
          description: deployment event stream
          eventDiscriminator:
            parameter: X-GitHub-Event
          parameters:
            - name: deployment
              in: body
              required: true
              schema:
                $ref: '#/definitions/deployment'
            - name: X-GitHub-Event
              in: header
              type: string
            - name: X-GitHub-Delivery
              in: header
              type: string
            - name: X-Hub-Signature
              in: header
              type: string      

Discriminator in the message Body

In this example, the eventDiscriminator is absent, and defaults to exploiting the discriminator defined in the schema for the body parameter.

x-async-responses:
  - event-id: AnimalStream
    description: animal event stream
    parameters:
      - name: animal
        in: body
        required: true
        schema:
          $ref: '#/definitions/Pet'

definitions:
  Pet:
    type: object
    discriminator: petType
    properties:
      name:
        type: string
      petType:
        type: string
    required:
    - name
    - petType
  Cat:
    description: A representation of a cat
    allOf:
    - $ref: '#/definitions/Pet'
    - type: object
      properties:
        huntingSkill:
          type: string
          description: The measured skill for hunting
          default: lazy
          enum:
          - clueless
          - lazy
          - adventurous
          - aggressive
      required:
      - huntingSkill
  Dog:
    description: A representation of a dog
    allOf:
    - $ref: '#/definitions/Pet'
    - type: object
      properties:
        packSize:
          type: integer
          format: int32
          description: the size of the pack the dog is from
          default: 0
          minimum: 0
      required:
      - packSize

Wider objectives not covered in this document

  • Support semantic tagging for the subscription APIs
    • In order to allow an SDK to support abstraction of the subscription mechanism
  • Support Business annotations
    • events, actions, and data can have business annotations, such as;
      • Display Name
      • Description
      • Semantic Tags
  • Support other event propagation protocols
    • Support swagger representation of other event propagation protocols, such as
      • Kafka
      • etc

Complete Sample swagger for GitHub

swagger: '2.0'
info:
  title: Webhooks example - for Github
  description: |
  version: 1.0.0
host: example.com:443
schemes:
  - https
basePath: /
produces:
  - application/json

paths:
  /repos/owner/repo/hooks:
    post:
      operationId: 'CreateHook'
      summary: Create a webhook in GITHUB
      description: |
        Call this API to create a new WebHook in Github
      parameters:
        - name: subscription
          in: body
          description: Details to subscribe for a callback on a given set of events
          required: true
          schema:
            $ref: '#/definitions/Subscription'
      tags:
        - Webhook
      responses:
        '202':
          description: Details of the subscription created to the webhook
          schema:
            $ref: '#/definitions/SubscriptionResponse'
      x-async-responses:
        - event-id: commentStream
          description: Comment event stream
          eventDiscriminator:
            in: X-GitHub-Event
          parameters:
            - name: comment
              in: body
              required: true
              schema:
                $ref: '#/definitions/CommentEventPayload'
            - name: X-GitHub-Event
              in: header
              type: string
            - name: X-GitHub-Delivery
              in: header
              type: string
            - name: X-Hub-Signature
              in: header
              type: string
        - event-id: deployment
          description: deployment event stream
          parameters:
            - name: deployment
              in: body
              required: true
              schema:
                $ref: '#/definitions/DeploymentEventPayload'
            - name: X-GitHub-Event
              in: header
              type: string
              event-discriminator-value: 'deployment'
            - name: X-GitHub-Delivery
              in: header
              type: string
            - name: X-Hub-Signature
              in: header
              type: string      
definitions:
  Subscription:
    type: object
    properties:
      name:
        type: string
      config:
        type: object
        properties:
          url:
            type: string
          content_type:
            type: string
      events:
        type: array
        items:
          type: string
      active:
        type: boolean

  SubscriptionResponse:
    type: object
    properties:
      id:
        type: number
      url:
        type: string
      test_url:
        type: string
      ping_url:
        type: string
      name:
        type: string
      events:
        type: array
        items:
          type: string
      active:
        type: boolean
      config:
        type: object
      updated_at:
        type: string
      created_at:
        type: string


  CommentEventPayload:
    type: object
    properties:
      action:
        type: string
      comment:
        $ref: '#/definitions/Comment'
      repository:
        $ref: '#/definitions/Repository'
      sender:
        $ref: '#/definitions/Sender'

  DeploymentEventPayload:
    type: object
    properties:
      deployment:
        $ref: '#/definitions/Deployment'
      repository:
        $ref: '#/definitions/Repository'
      sender:
        $ref: '#/definitions/Sender'  

  Comment:
    type: object

  Repository:
    type: object

  Sender:
    type: object

  Deployment:
    type: object



Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:13 (6 by maintainers)

github_iconTop GitHub Comments

0reactions
CGamesPlaycommented, Aug 6, 2018

Hello, in the initial proposal here:

  • Usage standalone
    • If x-async-responses appears at the top level, this indicates that the subscription happens via some unspecified mechanism.
    • It is common for systems that support WebHooks to provide a UI that allows the subscription to be performed, for example

This appears to have gotten lost in the various shuffles. Is there any current or planned method to document a callback that is not created from a specific path?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Callbacks - Swagger
In OpenAPI 3 specs, you can define callbacks – asynchronous, out-of-band requests that your service will send to some other service in response...
Read more >
Publishing asynchronous APIs. REST has become ... - Medium
Webhooks offer the ability for operations to occur over a longer period of time and have multiple responses. A server can receive a...
Read more >
Two OpenAPI 3.1 changes we love - Bump.sh
Here are two major changes we loved so much at Bump that we have already released their support. Webhooks support. This is one...
Read more >
What is a webhook? - Apideck Blog
An application subscribes to server events, and the server responds with a payload once an update occurs, typically sent in a JSON or...
Read more >
What's New in SwaggerHub - SmartBear Support
Option to export resolved json/yaml added for AsyncAPI definitions ... SwaggerHub mock server now honors null values in response and schema examples used...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found