Dirk Schumacher
Dirk Schumacher

Reputation: 1655

'Templating' on Swagger API Description with yaml

Is it possible to use templating w/ swagger. How is it done.
I do not want to repeat the three properties time, len and off each time.

Have a look at the end of this post where I made up a 'template' for explanation.

More Detail:

I have a JSON response structure which always returns a JSON always with the same properties but only the content of data is subject to change.

data could be an array, could be a string, a number, null or an object.
That depends on the Api's function handling.

{
  time: "2019-02-01T12:12:324",
  off: 13,
  len: 14,
  data: [
    "Last item in the row of 14 items :-)"
  ]
}

See at the end of this post for my example of the Swagger definition. It is a yaml which can be pasted into the swagger editor at https://editor.swagger.io/

In the swagger documentation (yaml) I do not want to repeat the statically reoccuring items, which will not change in their functionality for any other request.

Let me know, if the question is not precisely enough to understand.

swagger: "2.0"
info:
  description: ""
  version: 1.0.0
  title: "Templating?"
  contact:
    email: "[email protected]"

host: localhost
basePath: /api

paths:

  /items:
    get:
      summary: "list of items"
      produces:
        - application/json
      responses:
        200:
          description: "successful operation"
          schema:
            $ref: "#/definitions/Items"

  /item/{id}:
    get:
      summary: "specific item"
      produces:
        - application/json
      parameters: 
        - name: id
          in: path
          description: "ID of the demanded item"
          required: true
      responses:
        200:
          description: "successful operation"
          schema:
            $ref: "#/definitions/Item"

definitions:

  Items:
    type: object
    description: ""
    properties:
      time: 
        type: string
        format: date-time
        description: "date-time of the request"
      off:
        type: integer
        description: "index 0 based offset of list data"
        default: 0
      len:
        type: integer
        description: "overall amount of items returned"
        default: -1
      data:
        type: array
        items:
          $ref: "#/definitions/ListingItem"

  Item:
    type: object
    description: ""
    properties:
      time: 
        type: string
        format: date-time
        description: "date-time of the request"
      off:
        type: integer
        description: "index 0 based offset of list data"
        default: 0
      len:
        type: integer
        description: "overall amount of items returned"
        default: -1
      data:
        $ref: "#/definitions/InfoItem"

  ListingItem:
    type: integer
    description: "ID of the referenced item"

  InfoItem:
    type: object
    properties:
      id:
        type: string
      text:
        type: string

Based on @Anthon's answer it came to my mind that this is somewhat the construct I would need. Actually it is inheriting from a 'template':

...
templates:

  AbstractBasicResponse:
    properties:
      time: 
        type: string
        format: date-time
        description: "date-time of the request"
      off:
        type: integer
        description: "index 0 based offset of list data"
        default: 0
      len:
        type: integer
        description: "overall amount of items returned"
        default: -1

definitions:

  Items:
    type: object
    extends: AbstractBasicResponse
    properties:
      data:
        type: array
        items:
          $ref: "#/definitions/ListingItem"

  Item:
    type: object
    extends: AbstractBasicResponse
    properties:
      data:
        $ref: "#/definitions/InfoItem"

  ListingItem:
    type: integer
    description: "ID of the referenced item"

  InfoItem:
    type: object
    properties:
      id:
        type: string
      text:
        type: string
...

Upvotes: 1

Views: 938

Answers (1)

Anthon
Anthon

Reputation: 76578

You might not have to revert to full templating, there are two things within YAML that help with "undoubling" recurring data: anchors/aliases and merge keys.

An example of an anchor (introduced by &) referenced by an alias (*) would be:

definitions:

  Items:
    type: object
    description: ""
    properties:
      time: 
        type: string
        format: date-time
        description: "date-time of the request"
      off: &index
        type: integer
        description: "index 0 based offset of list data"
        default: 0
      len: &amount
        type: integer
        description: "overall amount of items returned"
        default: -1
      data:
        type: array
        items:
          $ref: "#/definitions/ListingItem"

  Item:
    type: object
    description: ""
    properties:
      time: 
        type: string
        format: date-time
        description: "date-time of the request"
      off: *index
      len: *amount
  data:

A YAML parser needs to be able to handle this, but since the alias points to the same object after loading, the code using the data might no longer work the same because of side effect in some cases depending on how the loaded data is processed.
You can have multiple aliases referring to the same anchor.

The merge key (<<) is a special key in a mapping with which you can pre-load that mapping where it occurs with a bunch of key-value pairs. This is most effective when used with a anchor/alias. With that you you some finer control and you could do:

  len: &altlen
    type: integer
    description: "overall amount of items returned"
    default: -1

and then

  len:
    <<: &altlen
    default: 42

Which would then be the same doing:

  len:
    type: integer
    description: "overall amount of items returned"
    default: 42

Merge keys are normally resolved at load time by the YAML parser, so there are no potential side-effects when using those even though they involve anchors and aliases.

Upvotes: 1

Related Questions