Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Either #57

Closed
ikitommi opened this issue May 20, 2014 · 50 comments
Closed

Support for Either #57

ikitommi opened this issue May 20, 2014 · 50 comments

Comments

@ikitommi
Copy link
Contributor

hi.

Would like to be able present a type of Either[Dog,Cat] (or in clojure (either Dog, Cat, Moose) in the Spec. Quite common construct in the FP land. Would be like a enum, but with values of any type.

Currently such a thing could be presented as a complex type with optional fields for all the value => at least the swagger-ui would be able to generate sample models (with all possible alternatives in place) for it. Not perfect, but ~works. Requires also special coercion in the server side to map back into Either.

http://www.scala-lang.org/api/2.11.0/index.html#scala.util.Either

https://github.com/Prismatic/schema/blob/master/test/cljx/schema/core_test.cljx#L194-L203

@ikitommi
Copy link
Contributor Author

... in JSON Schema this would be implemented most likely with oneOf like:

{
  "oneOf": [
    { "$ref": "Cat" },
    { "$ref": "Dog" }
  ]
}

fehguy added a commit that referenced this issue Sep 8, 2014
Update 04-models-with-composition.json
@webron
Copy link
Member

webron commented Sep 19, 2014

Okay, in Swagger 2.0 we explicitly decided not to support this. There are various issues with supporting it ranging from how deterministic such an API is to can most common development languages support this feature easily.

I'm closing this issue for now, but marking it as a proposal for the next version of the spec, so that we may revisit this decision.

@ahultgren
Copy link

I wonder, if I have a resource which sends a response as an array that contains both say articles and ads, how would i define such a response in swagger? Combining all properties in one response object is really ugly and kinda makes validation based on the spec useless. I think oneOf would be a good solution for this case, unless I've missed another way of doing it?

@webron
Copy link
Member

webron commented Nov 10, 2014

We thrive to describe deterministic APIs. Sending a single array of both articles and ads makes it that much more difficult to process, especially for strongly-typed languages, so we don't support it. If we can find an elegant way to do it, we'll be more than happy to add support for it.

wking added a commit to azurestandard/api-spec that referenced this issue Feb 11, 2015
…od/{id}' endpoints

People can have multiple payment methods associated with them, so we
need separate endpoints to manage those methods.

Because of the difficulty with adding a field for a few endpoints in
Swagger, I'm not documenting PUT for now (for details, see 03e139a,
public.json: Add 'POST /drops' to create a new drop, 2014-12-19).  I
am documenting the POST model used to create new objects though, since
uploaded credit card data (which we pass on to an external processor)
is more detailed than what we actually store locally.

Since we support multiple payment methods, collect the specific types
using anyOf [1], even though that's not actually supported by Swagger
2.0 [2].  Check the 'type' field to figure out which type you're
looking at.  Each payment-type model declares it as a required,
single-value enum.

[1]: http://spacetelescope.github.io/understanding-json-schema/reference/combining.html?highlight=allof#anyof
[2]: OAI/OpenAPI-Specification#57 (comment)
@jphastings
Copy link

@webron Which languages would be most important to support? I mentioned on IRC the use case of GeoJSON, which I think is an important structure to be able to validate:

{
  "type": "Point",
  "coordinates": [-3.0107731, 16.7733758]
}
{
  "type": "LineString",
  "coordinates": [[-3.0107731, 16.7733758], [-101.8314831,35.2090451]]
}

@davidsklar
Copy link

I am new to Swagger and have already encountered several areas where this would be useful. With respect to the deterministic-API goal, what are popular-enough strongly-typed languages that would have great difficulty processing, e.g. a heterogenous collection? (As long as the possible types of the collection were explicitly enumerated and were defined (in swagger and the other language) in an appropriate way to indicate a relationship (parent-class/child-class, etc) that played nice with the type system.

@stevage
Copy link

stevage commented May 25, 2015

I think I understand the reasons for discouraging people from designing APIs where different types of objects can appear in the same place. (The term "non-deterministic API" doesn't seem quite right to me though.)

But anyway, it's a bit of a problem for documenting existing APIs (or GeoJSON, above). I'm working on one at the moment where a certain response contains an array of "stops" and "lines", where each is basically:

{
  "type": "stop", # or "line"
  "result": {
     # other properties depend on type
  }
}

Obviously it's possible to implement this in Swagger but it's pretty hacky and requires duplication and having to explain in words what's going on.

@webron
Copy link
Member

webron commented May 26, 2015

This is not about API design only, this is also related to the ability to provide support for it in the various tools we offer around Swagger. Since there is a workaround for some cases, it may be good enough for now. That said. it does not mean it will not be considered for the next version, we just need to do it wisely.

@bgrant0607
Copy link

What is the workaround for unions, discriminated or otherwise?

The Kubernetes API has a number of such cases. We currently use an object with all optional fields, where only one of the fields is expected. For example, PersistentVolumeSpec may contain details specific to a particular storage backend (swagger 1.2, but I believe it would be similar in 2.0):
https://github.com/kubernetes/kubernetes/blob/master/api/swagger-spec/v1.json#L11994

@fehguy
Copy link
Contributor

fehguy commented Aug 18, 2015

I believe with the spec as-is, you would document the common shared parameters in a base schema and use a discriminator field to represent acceptable concrete types. For the next version of the spec, agreed this needs attention.

@Fresa
Copy link

Fresa commented Aug 20, 2015

I also agree this is needed to fully support polymorphism.

wking added a commit to azurestandard/api-spec that referenced this issue Oct 1, 2015
I landed the previous syntax in 168a97b (public.json: Add '{GET|POST}
/payment-methods' and 'GET /payment-method/{id} ' endpoints,
2015-02-11), which pointed out that anyOf isn't valid Swagger 2.0.
But it's looking like the consensus is around including it in the next
Swagger release [1].  The JSON Schema example I was following [2]
didn't use $ref in their example, but they do use $ref in their allOf
example [3].  This commit updates the existing anyOf uses to match
that syntax.

[1]: OAI/OpenAPI-Specification#57 (comment)
[2]: http://spacetelescope.github.io/understanding-json-schema/reference/combining.html#anyof
[3]: http://spacetelescope.github.io/understanding-json-schema/reference/combining.html#allof
@erikvanzijst
Copy link

Since there is a workaround for some cases, it may be good enough for now.

I've just run into this also, evaluating Swagger 2.0 for our existing API, but I'm not sure what the suggested workaround is?

@webron
Copy link
Member

webron commented Oct 6, 2015

@erikvanzijst - the workaround is related to when you have a common property between the options (such as type) which can be used as the discriminator. You can find more information about the discriminator in the spec itself.

https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#schemaDiscriminator
https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#composition-and-inheritance-polymorphism

@erikvanzijst
Copy link

Right. I'll have a look at that.

@witoldsz
Copy link

witoldsz commented Oct 8, 2015

@webron

We thrive to describe deterministic APIs. Sending a single array of both articles and ads makes it that much more difficult to process, especially for strongly-typed languages, so we don't support it.

This is the most ridiculous explanation I could possibly imagine about not supporting oneOf 😳

@IvanGoncharov
Copy link
Contributor

@witoldsz @webron I think this discussion shifted towards incompatibility with JSON Schema topic. So it became duplicate of #333. Can we move discussion there and close this issue?

@webron
Copy link
Member

webron commented Oct 9, 2015

@witoldsz - sometimes the wording I use is not the best, but even if you disagree there are probably better ways to express it. If you'd like to discuss it further, I'm all for it.

@IvanGoncharov - while they are certainly related, I think it should remain open. When we start actual work on the next version we'll do a consolidation of issues (there are a few that apply).

@arthurdm
Copy link
Contributor

arthurdm commented Apr 4, 2016

Hi. Is this the correct issue for tracking the inclusion of anyOff and oneOff into the first version of the OpenAPI Initiative spec? I have found many links back in here, but as the title says "Support for Either", I think it's worth the clarification.

The journey of trying to find a single issue that dealt with anyOff / oneOff took me to many different github issues and google group conversations, and I often encountered the response that this was "something to be considered for the next version".

I am encountering more and more users of RAML that went there simply because they could model their APIs using any part of JSON Schema. Granted, JSON Schema is not perfect and draft 4 seems a bit unattended, but it's still a spec many RESTful endpoints used before Swagger came along. So telling them to use Swagger is an uphill battle, specially when they are using the parts of the JSON Schema spec that are missing. If they can't model their current endpoints, why would they use Swagger? Nice tooling won't make up for an endpoint definition that doesn't properly describe or restrict the model. This is not meant to sound overcritical, it's just meant to report back what we're seeing in the field with customers.

My suggestion to the Open API Initiative members is to share this progression more openly, so that the whole community can help solve this. What are the specific blockers for code gen that anyOf/oneOff are causing? Which languages? Which swagger OS projects would work, and which would be broken as-is? Can language-specific limitations be placed on certain tool generators?

There's a lot of Swagger users out there that can help. If this information is already openly shared, a link in here would be great.

@fehguy
Copy link
Contributor

fehguy commented Apr 4, 2016

Hi Arthur, this is a fine place for your comment. It is not currently supported and not clear if it will be. Just because one can model in another format doesn't make a good case for adding it to the OAS on it's own, but we are seriously considering it. There are many problems with doing so, including proposed changes in JSON Schema draft 5, tooling considerations, etc. Supporting this may give end users enough rope to certainly hang themselves, so it's being considered carefully. Please just track this one, we're addressing the inclusion (or not) very soon.

@webron
Copy link
Member

webron commented Apr 4, 2016

@arthurdm thanks for the comment. Some of the issues are discussed in #333 (in... length).

As @fehguy mentioned above, just because another tool supports it, doesn't mean we should too. Our goal is not necessarily to attend all use cases (and the existing variety of options help).

We may end up saying we support these and and force the tools to try and handle the issues - I'm not sure we'll be doing our users a better service there though as some cases would require a lot of work to be supported (if they can be at all). That would lead to a different type of frustration - what's the point to be able to describe something if you can't actually use it? This is not just about the Swagger tooling (which are external to the OAI), but also true to any other tool developed out there. If we make it complicated to support, we may end up with less tools in the echo system. Do we tell users there are limitations? Do we tell tool developers they need to work harder? Just need to find the right balance.

@pdo400
Copy link

pdo400 commented Apr 5, 2016

anyOf is fundamental to a declarative schema. It's the or to allOf's and.

But I guess I care more about properly describing my API than having mediocre tooling around an improperly described API...

(And, sure, add more special cases like security rather than a general mechanism... THAT will make things easier to support... ??!?)

@fehguy
Copy link
Contributor

fehguy commented Apr 5, 2016

huh?

@witoldsz
Copy link

witoldsz commented Apr 6, 2016

+1
I also cannot understand the priorities here. What do I need "tools" for if
the spec is unable to describe the API of my endpoints. I am also not sure
why some guys here are telling the other how bad their API must be, knowing
nothing but the "oneOf" requirement about the case.

Regards,
Witold Szczerba
6 kwi 2016 00:59 "Patrick Whitesell" notifications@github.com napisał(a):

anyOf is fundamental to a declarative schema.

But I guess I care more about properly describing my API than having
mediocre tooling around an improperly described API...

(And, sure, add more special cases like security rather than a general
mechanism... THAT will make things easier to support... ??!?)


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#57 (comment)

@natebrunette
Copy link

A common case is expanding entities. For example, using the Stripe Api, it may return a string, int, or null by default, but if you ask for the entire entity, it will return an object instead.

Granted, I believe I could specify each type it could be and copy every property of the entity, but in doing so, I lose a lot of reusability, which is one of the reasons I chose to use the spec.

In my opinion, it's odd to let the spec be defined by what's possible in a subset of languages or tools. If the problem is with statically typed languages, that sounds like a problem for implementations in those languages to solve. If the problem is with code generation tools, that sounds like a problem for those projects to solve.

@lijo-jacob
Copy link

lijo-jacob commented May 1, 2016

Limiting the API Spec just because the tooling around it cannot support it does not make sense.

Here is a use case from the retail/search domain:-
A keyword search API could return oneOf

  1. Product Search Results
  2. A keyword search redirect (Searching for special list of keywords could be redirected to special pages)

Keyword search API:

Endpoint:
GET /search

Parameters:
type=keyword
q=makeup

Response could be any one of:-

  1. Search Results
{
  "totalProducts": 77,
  "products": [
    ......
  ],
  "refinements": [
    .......
  ],
  "categories": [
    .......
  ],
  "keyword": "RAV4"
}
  1. Search Redirects
{
  "searchRedirectTarget": {
    "targetScreen": "product",
    "targetValue": "P123456;skuId=246810",
    "targetUrl": "/my-toyota-rav4"
  },
  "keyword": "RAV4"
}

@MatMoore
Copy link

MatMoore commented May 1, 2016

If OpenAPI wants to be agnostic about design-first vs code-first, then the specification has to be able to adequately describe real world APIs.

I don't think any decisions about inclusion in the specification should be determined by how easy or hard it is for a tool to implement. That is a problem that can be solved elsewhere, and if tool authors don't want to deal with it, then let them implement workarounds. By omitting something like this from the spec entirely you just force the problem on the users.

@webron
Copy link
Member

webron commented May 2, 2016

Umm, allowing users to describe anything but have no tooling support doesn't change the problem being forced on the user - it just moves the problem from the design phase to the implementation or use phases. This is about keeping an ecosystem that works and plays well together - and yes, that may impose a limitation on design. Reiterating what's been said all along - supporting the entire spectrum of API designs is not the goal, but we're definitely looking to expand the percentage with each release, in a sustainable manner. Yes, some real world APIs will not be described by the OAS.

This is an old thread, and I don't remember all the details about it, and my opinions change over time too. Sometimes the problem is not with the 'what' we want to support but rather 'how'. This is definitely an issue we're going to try and tackle. We have yet to start dealing with this request.

@blindsteal
Copy link

I just stumbled upon this issue and can barely believe that this hasn't been resolved after 2 (!) years. I am currently working on a 'real world' project implementing an API, and having to use type: any instead of the proper types with 'anyOf' is a serious limitation.
I can just guess why this issue hasn't gotten as much attention as it deserves: it is not common with statically typed languages where handling optional fields causes great pain (think Javas message format classes for deserialization, Go is similar I believe). Users of those languages seem to be the main audience of Swagger/OAI tooling).
As of today however there is plenty of languages (Node, Ruby, Python, browser-based JS come to mind) that have absolutely no problem with that kind of API design. It is often even preferable to an increased number of endpoints or a 'wide-table'-like schema with a lot of optional attributes (see for example the search example mentioned).
So +1 from me, don't let us hipster language users down ;)

@jookshub
Copy link

jookshub commented Jun 7, 2016

Hi guys,

after reading a lot, about this issue, I just want to throw in my vote for this to be supported soon.

If I understand all correctly it is currently not possible to state that an array must only consist of objects of a matching some given types?

My issue is simple, except in openAPI this seems not to be possible: have an array of articles that can have article-object that are either of type news or slides.

I want to use it for a teaser carousel, hence it is not possible to create something like this:

  articles:
    type: array
    items:
      $ref: "#/definitions/article"

article:
    type: object
    required:
      - id
      - headline
    properties:
      id:
        type: number
        format: int64
      headline:
        type: string
      content:
          anyOf:
            - $ref: "#/definitions/news"
            - $ref: "#/definitions/video"

Instead there is this discriminator Solution:

article:
    type: object
    discriminator: articleType
    required:
      - id
      - headline
      - articleType
    properties:
      id:
        type: number
        format: int64
      headline:
        type: string
      articleType:
        type: string
        default: news
        enum:
          - news
          - video          

However, this solutions leads to false warnings, if you do not use news or video as a reference somewhere else (is already a bug-ticket somewhere).

Further, I don't get how this discriminator-Field helps? At least in the Editor, it is not even mentioned nor does anything seem to be different. And I can't see the sub-type-details through the article, only the type.

Hope anyOf will be supported soon, this feels like a gap.

@fehguy
Copy link
Contributor

fehguy commented Jun 7, 2016

@blindsteal the fact that it hasn't been addressed isn't due to sheer laziness. It's because it hasn't made sense for a variety of reasons. You can read up on the history, etc., but we don't add support for things that we don't think belong in the spec. Not saying it won't ever happen, but if we just did everything that people asked for without thinking about the impact, we'd end up with a useless ball of mud.

@IvanGoncharov
Copy link
Contributor

@fehguy @jookshub I would suggest to find some middle ground. I think discriminator was a move in the right direction, but we need to provide an improved version of it. So I would love to hear your opinion on #707.

@blindsteal
Copy link

hi @fehguy ! I didn't mean to imply it was because of laziness, sorry 😁 I was just surprised because the history of this thread actually read like 4 out of 5 people were agreeing with the endeavour.
discriminator solves a lot of my problems though, and probably the rest will vanish if #707 gets resolved :)

@fehguy
Copy link
Contributor

fehguy commented Jun 10, 2016

@blindsteal consider joining the convo on #707 with some example use cases that discriminator may help with

@webron
Copy link
Member

webron commented Jul 21, 2016

Tackling PR: #741

@fehguy
Copy link
Contributor

fehguy commented Aug 11, 2016

allOf, oneOf, not will be supported in 3.0 spec. Approval by @OAI/tdc in comments, implementation details will be in this PR:

#741

@webron
Copy link
Member

webron commented Feb 22, 2017

Changes are in, closing as done!

@luispabon
Copy link

It's a shame this never made it to swagger 2. Makes it hacky to describe JSONAPI interfaces where lists can be of mixed types (for instance, includes).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests