Forum Discussion

HenrikHL's avatar
HenrikHL
Frequent Contributor
10 months ago

The use of oneOf or anyOf in arrays

Hi all,

We have been discussing internally of how to use the oneOf and anyOf keywords in arrays.

Suppose we have the following 2 items (Dog and Cat)

 

Dog:
  type: object
  properties:
    name:
      type: string
    legs:
      type: number
Cat:
  type: object
  properties:
    name:
      type: string
    owner:
      type: string

 

I now want an "animals" list. What is the difference between the following two specifications:

 

animals:
  type: array
  items:
    anyOf:
      - $ref: Dog
      - $ref: Cat

 

and

 

animals:
  type: array
  items:
    oneOf:
      - $ref: Dog
      - $ref: Cat

 

If anybody has a link to an official documentation that would be great.

What I am looking for is a list like this:

 

{
  "animals": [
    {
      "name": "King",
      "legs": 4
    },
    {
      "name": "White",
      "owner": "John"
    }
  ]
}

 

Which is a list containing both Dog and Cat objects

6 Replies

  • chichepo's avatar
    chichepo
    Champion Level 3

    Hi HenrikHL 

    I guess you are working with OAS 3.0.x.

    You get reach this page or this page or this page to further documentation:

    I got this structure after playing with arrays and items:

    In conclusion, the difference in the way both items are validated.

    Regarding the expected list, did you try something like that?

     

     

     




  • HenrikHL's avatar
    HenrikHL
    Frequent Contributor

    Hi chichepo 

    Thanks for your comments. Yes I am using 3.0.x

    Can you please explain a little more what you mean by:

    In conclusion, the difference in the way both items are validated.

    I can see the example code generated by Swagger for both lists are the same? If the difference is in the validation - which of the two lists is correct? The one using oneOf or the one using anyOf?

    Regarding your example above I assume you meant type: array and not type:string for "Animals" πŸ˜‰

    When I read the documentation for oneOf vs anyOf (you made a screenshot above) - then it makes me think that for arrays:

    When anyOf is used in an array - then each item in the array can be:

    • a Dog followed by a Cat
    • a Cat followed by a Dob
    • just a Dog
    • just a Cat

    When oneOf is used in an array - then each item in the list can be exactly a Dog or a Cat.

    In my opinion oneOf is the correct use for the above example-lists...?

  • HenrikHL's avatar
    HenrikHL
    Frequent Contributor

    According to this article: https://www.baeldung.com/openapi-array-of-varying-types

    When using oneOf - each item in the list must be either of type Dog OR type Cat (https://www.baeldung.com/openapi-array-of-varying-types#1-oneof-keyword)

    When using anyOf - then the items in the list can be a merge of Dog AND Cat (https://www.baeldung.com/openapi-array-of-varying-types#2-anyof-keyword)

     

    If this article is correct - then the autogenerated examples on SwaggerHub are wrong.

    • chichepo's avatar
      chichepo
      Champion Level 3

      HenrikHL 

      My apologies for the error in my first example. Please look at the updated screen shot.

      Regarding your specific case, to achieve your expected structure, you will have to use anyOf, since it admits a mix of both items types.
      Even if it looks like identical, the validation (specification) behavior is different.
      If you are working with some API gateway, (AWS, APIGEE, etc.) you will be able to test the validation according to your specifications.

      Regarding the SwaggerHub rendering, don't be surprised if you don't got the exact structure form.
      Especially for such kind of "polymorphism".
      It makes sense by the way.
      How do you want to render such a complex structure? In allOf, for example, should it display the first definition or the second?

      Let us know πŸ˜‰


  • HenrikHL's avatar
    HenrikHL
    Frequent Contributor

    chichepo no worries - I understood the example πŸ˜‰

    With the autogenerated examples I would assume that:

    anyOf would generate:

    "animals": [
        {
          "name": "string",
          "legs": 0
        },
        {
          "name": "string",
          "owner": "string"
        }
      ]

    and oneOf would generate:

    "animals": [
        {
          "name": "string",
          "legs": 0
        },
        {
          "name": "string",
          "legs": 0
        }
      ]

    (Here the first item in the oneOf would just be repeated twice...)

     

    Where in the specifications does it specify that the oneOf or anyOf applies to the entire list and not to each item in the list?

    My assumption was that below the keyword "items" - the structure for each item in the list is specified. This could be a type:string - in which case all items in the list would have to be of type string. In case it is a oneOf - then each item in the list would be a oneOf... Again - this is just my (maybe wrongly) assumption - it would be great to read an official specification for the use of oneOf and/or anyOf in combination with an array (items field) πŸ™‚

    • chichepo's avatar
      chichepo
      Champion Level 3

      Sorry for my late answer but your question is about a particular point that is still under discussion by us as well.

      As far as I understand the purpose of oneOf, anyOf and allOf, it's a kind of scaffold for polymorphism validation.
      Again, I am not expected anything from SwaggerHub preview and, by the way, the resolved YAML/JSON are identical (like you mentioned).
      I would expect, in your specific case,  to get the exact Dog/Cat structure, even under an array items (including items characteristics).

      For example, in our architecture convention, the oneOf/anyOf have a specific model in our code (then we are free to add our own validations within)


      I'll be happy to get some comments, from the community, about the following facts:
      - Not all the code generators are supporting oneOf, anyOf and allOf. (depending on the target language).

      - I don't know if there is a OAS YAML/JSON generator that support it.
      - AWS Gateway and APIGEE are not supporting it (or very partially)

      Let us know