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 multiple $refs inside a single object #417

Closed
glen-84 opened this issue Jul 17, 2015 · 42 comments
Closed

Support for multiple $refs inside a single object #417

glen-84 opened this issue Jul 17, 2015 · 42 comments
Labels
Moved to Moonwalk Issues that can be closed or migrated as being addressed in Moonwalk re-use: ref-group-combine Re-use requests involving grouping components and combining groups

Comments

@glen-84
Copy link

glen-84 commented Jul 17, 2015

It would be really useful to be able to do something like this:

paths:
    $ref: "/operations/pets.yaml"       # Multiple paths
    $ref: "/operations/stores.yaml"     # Multiple paths
    $ref: "/operations/users.yaml"      # Multiple paths

Where each file includes multiple paths. For example (pets.yaml):

/pets:
  post:
    # ...
/pets/findByStatus:
  get:
    # ...

This would make it easier to organize a large API.

Edit:

It could also be an array, like this:

paths:
    $ref:
        - "/operations/pets.yaml"
        - "/operations/stores.yaml"
        - "/operations/users.yaml"
@IvanGoncharov
Copy link
Contributor

Swagger spec, define '$ref' as follows:
The Reference Object is a JSON Reference that uses a JSON Pointer as its value.

References used through entire spec and most importantly inside Schema object.
What mean if $ref behaviour will change it will totally ruin compatibility with JSON Schema and JSON Reference and all tooling which being build around them.

Another problem is how you would handle merge conflicts?
For example /operations/pets.yaml and /operations/stores.yaml both have same key inside.
Or one contain an object and another an array.

But I totally support your idea about allowing to split paths into separate files.
Instead of reinventing the wheel, we could use RAML approach to this problem. And make paths recursive structure, so your example will look like this:

paths:
  /pets:
    $ref: "/operations/pets.yaml"       # Multiple paths
  /stores:
    $ref: "/operations/stores.yaml"     # Multiple paths
  /users:
    $ref: "/operations/users.yaml"      # Multiple paths

And 'pets.yaml' will looks like this:

post:
  # ...
/findByStatus:
  get:
    # ...

@glen-84 Is this proposal will solve your problem?

P.S. It could also solve path parameters duplication problem.

@glen-84
Copy link
Author

glen-84 commented Jul 17, 2015

It's quite surprising to me that the existing standards don't support this. I don't suppose this is likely to change?

As for merge conflicts, if I create two equal paths with the Swagger editor, it just uses the last one. It could be the same, or it could be a setting if you want it to throw an error.

Nested paths might be an option, although it feels a bit weird having the nested paths at the same level as post/get etc.

Could allOf be used at all?

paths:
    allOf:
        - $ref: "/operations/pets.yaml"
        - $ref: "/operations/stores.yaml"
        - /users:
            get:
                # ...

... that may be completely incorrect or make no sense – I don't know very much about JSON schema. 😄

@IvanGoncharov
Copy link
Contributor

I don't suppose this is likely to change?

In any case it should be changes to JSON Pointer spec.

Could allOf be used at all?

No, 'allOf' supported only inside Schema Object.
Swagger is very strict format and you can see all supported fields here

mohsen1 pushed a commit to mohsen1/swagger-spec that referenced this issue Oct 2, 2015
mohsen1 pushed a commit to mohsen1/swagger-spec that referenced this issue Oct 2, 2015
Samples for swagger-js/OAI#417: Separated files, yaml only for now
@kulkarniankita
Copy link

+1 for adding allof to paths so multiple paths/APIs can be referenced

@wannabesrevenge
Copy link

+1 I am looking for any work around right now for allowing path urls and their subsequent path objects to be defined in multiple external files. Does anyone have any suggestions?

@glen-84
Copy link
Author

glen-84 commented May 7, 2016

@wannabesrevenge I'm currently using something like this:

paths:
    # Blogs
    # -- Blogs
    /blogs:
        $ref: "operations/blogs/blogs.yaml#/Blogs"
    /blogs/{id}:
        $ref: "operations/blogs/blogs.yaml#/Blog"
    # -- Blog Posts
    /blogs/{id}/posts:
        $ref: "operations/blogs/blog-posts.yaml#/BlogPosts"
    /blogs/posts/{id}:
        $ref: "operations/blogs/blog-posts.yaml#/BlogPost"
    /blogs/posts/{id}/comments:
        $ref: "operations/blogs/blog-posts.yaml#/BlogPostComments"

I don't think it's possible to move the actual paths to separate files.

@wannabesrevenge
Copy link

That's a shame. I'm hoping that "merge" in JSON schema v5 (i think it's v5) will help. I settled for doing this the same way as you. In one way it's nice because its explicit, but it is definitely not completely DRY in principle. Now if we add a route to one microservice api, we must also add the route to the master api.

@Giri-oss
Copy link

+1 for supporting recursive structure for paths

@OhDavit
Copy link

OhDavit commented Aug 30, 2016

+1 need this

@danitome24
Copy link

+1

@LandonSchropp
Copy link

👍 for this appraoch:

paths:
    $ref:
        - "/operations/pets.yaml"
        - "/operations/stores.yaml"
        - "/operations/users.yaml"

It's simple and easy to understand.

@IvanGoncharov: I could think of a couple ways to resolve conflicts. Apologies if I'm missing something large here, but it seems like you could do something like this:

  • If the references are both objects, the later values for the keys overwrite the earlier values for the keys. This would work the same way Object.assign() overwrites values.
  • If they're both arrays, they're concatenated.
  • Otherwise, the second reference overwrites the first (strings, booleans, etc.).

@erikfox
Copy link

erikfox commented Nov 21, 2016

@LandonSchropp I agree. Would pleasantly mimic familiar Object.assign() behavior here.

Merging objects with same properties

var o1 = { a: 1, b: 1, c: 1 };
var o2 = { b: 2, c: 2 };
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

The properties are overwritten by other objects that have the same properties later in the parameters order.

@darrelmiller
Copy link
Member

Folks, I'm afraid you are pitching to the wrong people. OpenAPI uses $ref as it is defined by JSON Schema. If you want $ref 's behavior to be changed, you need to convince the JSON Schema folks to change it. The alternative is to define a completely new re-use mechanism so there is no confusion between reuse within JSON Schemas and reuse elsewhere.

@erikfox
Copy link

erikfox commented Nov 22, 2016

Thanks @darrelmiller!

For anyone interested in supporting this proposal, I've re-created this issue in the correct repo.

@webron
Copy link
Member

webron commented Nov 22, 2016

FWIW, JSON References (and JSON Pointers) are actually not part of JSON Schema, but JSON Schema uses them. They were both originally written by the same people (iirc), but that doesn't mean the current JSON Schema folks actually maintain JSON Reference as well, but we'll see their response.

@darrelmiller
Copy link
Member

@webron You are correct that there is a distinct spec for JSON Reference, but for some reason the wording describing $ref was duplicated in the JSON Schema spec https://tools.ietf.org/html/draft-wright-json-schema-00#section-7 which leaves us in an ambiguous state. Considering there are people actually working on the JSON Schema now, it might actually be the best place to get change to happen.

@webron
Copy link
Member

webron commented Nov 22, 2016

@darrelmiller - right, only you're not looking at draft 4 which is our official reference for the spec, where JSON References explicitly point to JSON Reference.

Of course, hopefully by the time official word on the next draft/version of JSON Schema is out, it will be clarified better than what you've shown. And who knows, maybe we'll drop JSON Schema and move to something... better.

@fehguy
Copy link
Contributor

fehguy commented Nov 22, 2016

@webron there is nothing better, there are no known valid problems with JSON schema 😆

@alexander-larchenko
Copy link

alexander-larchenko commented May 25, 2017

@glen-84 can you explain how your abovementioned solution works?

paths:
# Blogs
# -- Blogs
/blogs:
$ref: "operations/blogs/blogs.yaml#/Blogs"
/blogs/{id}:
$ref: "operations/blogs/blogs.yaml#/Blog"
# -- Blog Posts
/blogs/{id}/posts:
$ref: "operations/blogs/blog-posts.yaml#/BlogPosts"
/blogs/posts/{id}:
$ref: "operations/blogs/blog-posts.yaml#/BlogPost"
/blogs/posts/{id}/comments:
$ref: "operations/blogs/blog-posts.yaml#/BlogPostComments"

when i try to replicate it, it always inserts "Blogs" node below the /blogs
i end up with

paths:
    # Blogs
    /blogs:
        Blogs:  #this shouldnt be here. How to get rid of it?
           get: ....

@glen-84
Copy link
Author

glen-84 commented May 27, 2017

@alexander-larchenko,

Are you using the #/Blogs reference?

The target file should be structured as follows:

Blogs:
    get:
        summary: Get a list of blogs
        tags:
            - Blogs
        responses:
            etc.

I'm using swagger-parser (v3.4.1) to dereference the file.

@alexander-larchenko
Copy link

@glen-84,

Are you using the #/Blogs reference?

Yes, I tried to replicate your example fully, just to see how it goes.
But I'm using Swagger CLI for bundling and it provides a different result for this way of referencing. That's why you have swagger-parser to handle those references correctly. Right?

@glen-84
Copy link
Author

glen-84 commented May 29, 2017

That's why you have swagger-parser to handle those references correctly. Right?

Most likely, yes.

I may have started using swagger-parser because of apigee-127/swagger-tools#227.

@rayarikar
Copy link

After reading through the entire conversation it looks like we do not have any way to do something similar to this or any variation similar to the below

paths:

  • $ref: yaml1.yml
  • $ref: yaml2.yml

Please correct me if I am wrong. How are other folks serving a single yml file which serves multiple paths spread across children ymls?

@elboletaire
Copy link

@rayarikar in my case I'm using the discriminator object; for merging values the one I'm using is allOf:

components:
  schemas:
    First:
      type: object
      items:
        first:
          type: string
    Second:
      type: object
      items:
        second:
          type: string
paths:
  /:
    post:
      requestBody:
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/First'
              - $ref: '#/components/schemas/Second'

@mitar
Copy link

mitar commented Apr 24, 2018

You mean oneOf? allOf would probably make it not match anything?

@elboletaire
Copy link

elboletaire commented Apr 24, 2018

allOf will take all the definitions. I want all the definitions to be merged, not just one of the specified definitions.

@fenollp
Copy link

fenollp commented Apr 24, 2018

Would YAML’s own pointers solve your issue? I’m not sure how merging happens though but that could be a solution usable today

@elboletaire
Copy link

Who are you asking to? BTW, I don't think that using a file format specific solution is a good idea here when OpenAPI spec allows other file formats (like json).

@chrisdostert
Copy link

This does it https://github.com/WindomZ/swagger-merger . Would love to see this type of support in the official tooling

example:

paths:
  /path1:
    $ref: https://someurl/openapi.yaml
  /path2:
    $ref: https://someurl2/openapi.json

@darrelmiller
Copy link
Member

@chrisdostert The example you are showing is actually valid OpenAPI. This is a exceptional usage of $ref in the PathItemObject where $ref is a fixed field. It doesn't behave the same way as the other reference objects in an OpenAPI document.

However, this only allows referencing a single path at a time. There is no way to reference a document that contains a set of paths.

@francescobianco
Copy link

@glen-84 I suggest building a file using command line toolkit that links multiple YAML files with $include tag. Look this https://github.com/javanile/yamlinc add-in project task using gulp or grunt. Any considerations @IvanGoncharov @kulkarniankita @wannabesrevenge @BabuGiri

@waseem-khan-dev
Copy link

waseem-khan-dev commented Feb 20, 2020

This is working fine for me

 "requestBody": {
      "required": True,
      "content": {
        "application/json": {
          "schema": {
            "allOf": [{
              "$ref": "#/definitions/First"
            }, {
              "$ref": "#/definitions/Second"
            }]
          }
        }
      }
    }

@handrews
Copy link
Member

@waseem-khan-dev yes, that works fine in the Schema Object, but this was reported against the Path Object where allOf is not available.

@webron @MikeRalphson @whitlockjc this is another Path Object $ref issue, but a rather specific one. I don't recall any drive to try to have a multi-$ref feature in Path Objects. Is this worth keeping open for 4.0, or should we close it?

It will definitely not be further addressed in JSON Schema, because allOf handles things there.

@s97712
Copy link

s97712 commented Mar 23, 2020

Why not use arrays?

.. ..
paths Paths Object | [Paths Object with path]

Path Item Object With Path

.. ..
path /{path}
...Paths Object ...
...

paths:
  - $ref: "/pets.yaml"
  - $ref: "/users.yaml"
  - path: /stores
    post: 
      ...
...

@picardplaisimond
Copy link

picardplaisimond commented May 29, 2021

It's 2021, and we still don't have a solution for this problem.
I also think that we should be (at least) able to use arrays for this.

@hello02923
Copy link

Maybe this will be useful for you!

Result:
  type: object
  allOf:
    - $ref: '#/definitions/exampleA'
    - $ref: '#/definitions/exampleB'

@proohit
Copy link

proohit commented Aug 24, 2021

Maybe this will be useful for you!

Result:
  type: object
  allOf:
    - $ref: '#/definitions/exampleA'
    - $ref: '#/definitions/exampleB'

As stated by #417 (comment) this applies to Schema Object but not all objects, i.e. not the global paths object. See Paths Object which does not state any use of allOf or $ref in any case.

jerstlouis referenced this issue in opengeospatial/ogcapi-processes May 31, 2023
Add short documentation on how to generate the desired files.

Small fix to make operationId unique
@asarra
Copy link

asarra commented Aug 31, 2023

It's 2021, and we still don't have a solution for this problem. I also think that we should be (at least) able to use arrays for this.

3 months until 2024 and we still do not have it ...

@handrews
Copy link
Member

@asarra most attention now is on OAS 4 (a.k.a. "Moonwalk") which will address this sort of problem more thoroughly.

@asarra
Copy link

asarra commented Aug 31, 2023

@asarra most attention now is on OAS 4 (a.k.a. "Moonwalk") which will address this sort of problem more thoroughly.

Ty that's good to read

@Jackman3005
Copy link

Jackman3005 commented Sep 1, 2023

@asarra most attention now is on OAS 4 (a.k.a. "Moonwalk") which will address this sort of problem more thoroughly.

Where can we read the current draft of OAS 4? I couldn't seem to find it myself.

Edit: Found it. "moonwalk" was the missing keyword in my search.

https://github.com/OAI/moonwalk

@handrews handrews added the Moved to Moonwalk Issues that can be closed or migrated as being addressed in Moonwalk label Jan 27, 2024
@handrews
Copy link
Member

Closing as "moved to moonwalk" which was already the conclusion in the last few comments.

@handrews handrews added re-use: ref-group-combine Re-use requests involving grouping components and combining groups and removed $ref labels Feb 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Moved to Moonwalk Issues that can be closed or migrated as being addressed in Moonwalk re-use: ref-group-combine Re-use requests involving grouping components and combining groups
Projects
None yet
Development

No branches or pull requests