Search code examples
swaggerdefinitionsopenapi

Creating an extendible model using Swagger/ OpenAPI


In my API i would like to have a simple model for my collection and a more elaborate model for my individual resource. For example:

a GET request on /libraries should return

BaseLibrary:
    type: object
    properties:
        library_id:
          type: string
          description: The id of the library
        display_name:
          type: string
          description: Name of the library
        href:
          type: string
          description: The URI linking to this library.

whilst a request to a specific library should return all of the above including an extra parameter books:

So a GET request to libraries/{library_id} should return:

ExtendedLibrary:
    type: object
    properties:
        library_id:
          type: string
          description: The id of the library
        display_name:
          type: string
          description: Name of the library
        href:
          type: string
          description: The URI linking to this library.
        books:
          type: array
          description: The books in this library
          items:
            $ref: "#/definitions/books"

I would very much like to not have to define a "BaseLibrary" twice and would want to simple model an additional "ExtendedLibrary" which contains all the responses of a base library and the additional books property.

I tried a lot of different things, with the closest to succes being the following definitions:

definitions:
  BaseLibrary:
    type: object
    properties:
        library_id:
          type: string
          description: The id of the library.
        display_name:
          type: string
          description: Name of the library
        href:
          type: string
          description: The URI linking to this library.

  ExtendedLibrary:
    type: object
    properties:
      $ref: "#/definitions/BaseLibrary/properties"
      books:
        type: array
        description: The available books for this library.
        items:
          $ref: "#/definitions/Book"

However this gives me a "Extra JSON reference properties will be ignored: books" warning and the output seems to ignore this extra property. Is there a clean way to handle my problem? Or am I just going to have to copy paste my whole BaseLibrary model into my ExtendedLibrary model?


Solution

  • As mentioned in the comments section, this may be a duplicate of another question, but it's worth repeating the answer in the context of this particular example. The solution is to use the allOf property in the definition of ExtendedLibrary:

    definitions:
      Book:
        type: object
        properties:
          title:
            type: string
          author:
            type: string
    
      BaseLibrary:
        type: object
        properties:
          library_id:
            type: string
            description: The id of the library
          display_name:
            type: string
            description: Name of the library
          href:
            type: string
            description: The URI linking to this library.
    
      ExtendedLibrary:
        type: object
        allOf:
          - $ref: '#/definitions/BaseLibrary'
          - properties:
              books:
                type: array
                description: The books in this library
                items:
                  $ref: "#/definitions/Book"
    

    In my experience, Swagger UI visualizes this correctly. When I define an operation response to be ExtendedLibrary Swagger UI shows this example:

    {
      "library_id": "string",
      "display_name": "string",
      "href": "string",
      "books": [
        {
          "title": "string",
          "author": "string"
        }
      ]
    }
    

    Also, Swagger Codegen does the right thing. At least when generating a Java client, it creates an ExtendedLibrary class that correctly extends BaseLibrary.