3

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?

PdevG
  • 3,427
  • 15
  • 30
  • 1
    This seems to be a question about inheritance and/or composition. It may be a duplicate of http://stackoverflow.com/questions/27862407/swagger-inheritance-and-composition. I recommend reviewing those answers. In particular, look at the examples of the **allOf** property. If that doesn't help, let us know. – Dave Delay Feb 28 '17 at 22:46
  • First of all thanks for the response. allOf does seem to do what I would like it to do, however in the UI it fails to show an Example Value and instead shows [ {} ] Is this normal behaviour? I assumed because of this that it didn't work. – PdevG Mar 01 '17 at 09:55
  • Which UI are you referring to? The Swagger Editor or Swagger UI? I just spent some time testing use of **allOf** in both apps. They both seem to have trouble visualizing **allOf** -- but the symptoms are different. I'm also starting to wonder how Swagger Codegen will handle it. So **allOf** may not be completely supported by all Swagger tools. Personally, I would do more research (and perhaps ask more questions) before diving in. – Dave Delay Mar 01 '17 at 16:39
  • I was referring to the Swagger UI, in the Swagger Editor it looked weird, but I figured only the Swagger UI is important as a source of documentation. However in the Swagger UI it was even worse and I got the empty list. Maybe ill start stalking the swagger github for answers on how to proceed. Thanks for your input and for going through the trouble of testing it :). – PdevG Mar 01 '17 at 17:04
  • It turns out that this is a known bug in the UI at the moment. allOf is the way to go :) – PdevG Mar 02 '17 at 07:54
  • I also did a little more research and posted a proper answer to your question. Please accept the answer if it works for you. – Dave Delay Mar 02 '17 at 16:03

1 Answers1

2

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.

Community
  • 1
  • 1
Dave Delay
  • 1,292
  • 8
  • 12