32

I'm trying to build a Swagger model for a time interval, using a simple string to store the time (I know that there is also datetime):

definitions:
  Time:
    type: string
    description: Time in 24 hour format "hh:mm".
  TimeInterval:
    type: object
    properties:
      lowerBound:
        $ref: "#/definitions/Time"
        description: Lower bound on the time interval.
        default: "00:00"
      upperBound:
        $ref: "#/definitions/Time"
        description: Upper bound on the time interval.
        default: "24:00"        

For some reason the generated HTML does not show the lowerBound and upperBound "description", but only the original Time "description". This makes me think I'm not doing this correctly.

So the question is if using a model as a type can in fact be done as I'm trying to do.

Helen
  • 87,344
  • 17
  • 243
  • 314
mvc
  • 653
  • 1
  • 5
  • 9

1 Answers1

39

TL;DR: $ref siblings are supported (to an extent) in OpenAPI 3.1. In previous OpenAPI versions, any keywords alongside $ref are ignored.

OpenAPI 3.1

Your definition will work as expected when migrated to OpenAPI 3.1. This new version is fully compatible with JSON Schema 2020-12, which allows $ref siblings in schemas.

openapi: 3.1.0
...

components:
  schemas:
    Time:
      type: string
      description: Time in 24 hour format "hh:mm".

    TimeInterval:
      type: object
      properties:
        lowerBound:
          # ------- This will work in OAS 3.1 ------- #
          $ref: "#/components/schemas/Time"
          description: Lower bound on the time interval.
          default: "00:00"
        upperBound:
          # ------- This will work in OAS 3.1 ------- #
          $ref: "#/components/schemas/Time"
          description: Upper bound on the time interval.
          default: "24:00"  

Outside of schemas - for example, in responses or parameters - $refs only allow sibling summary and description keywords. Any other keywords alongside these $refs will be ignored.

# openapi: 3.1.0

# This is supported
parameters:
  - $ref: '#/components/parameters/id'
    description: Entity ID

# This is NOT supported
parameters:
  - $ref: '#/components/parameters/id'
    required: true

Here're some OpenAPI feature requests about non-schema $ref siblings that you can track/upvote:

OpenAPI 2.0 and 3.0.x

In these versions, $ref works by replacing itself and all of its sibling elements with the definition it is pointing at. That is why

      lowerBound:
        $ref: "#/definitions/Time"
        description: Lower bound on the time interval.
        default: "00:00"

becomes

      lowerBound:
        type: string
        description: Time in 24 hour format "hh:mm".

A possible workaround is to wrap $ref into allOf - this can be used to "add" attributes to a $ref but not override existing attributes.

      lowerBound:
        allOf:
          - $ref: "#/definitions/Time"
        description: Lower bound on the time interval.
        default: "00:00"

Another way is to use replace the $ref with an inline definition.

definitions:
  TimeInterval:
    type: object
    properties:
      lowerBound:
        type: string  # <------
        description: Lower bound on the time interval, using 24 hour format "hh:mm".
        default: "00:00"
      upperBound:
        type: string  # <------
        description: Upper bound on the time interval, using 24 hour format "hh:mm".
        default: "24:00"
Helen
  • 87,344
  • 17
  • 243
  • 314
  • If `TimeInterval` in this example is a class from which the swagger definition is generated -- the class might have Swagger Annotations too -- do you know how to code the class and/or annotations so that it generates either of the workarounds in this answer (i.e. using `allOf`, or using an inline definition instead of `$ref`)? – ChrisW Nov 22 '19 at 23:25
  • @ChrisW I don't know, sorry. Try [asking a new question](/questions/ask) about annotations. – Helen Nov 25 '19 at 07:49
  • Thank you. There already is such a question ([here](https://stackoverflow.com/q/57459520/49942)), I wondered if you just happened to know. I think I'll try to implement it by (instead of annotations) constructing a model instance for the class, and injecting that custom model instance via a ModelResolver. – ChrisW Nov 25 '19 at 07:54
  • 2
    @Helen, Can you provide the official docs link of Open API stating the use of $ref along side the siblings is supported officially ? As per official docs go for Open API [here](https://swagger.io/docs/specification/using-ref/#sibling) use of siblings along side $ref is not supported. – Chaitanya Babar Mar 24 '21 at 07:38