Openapi-specification: OpenAPI.next: Allow recursive paths

Created on 11 Apr 2016  路  14Comments  路  Source: OAI/OpenAPI-Specification

In OpenAPI 2.0 paths like /user/{userId}/ and /user/{userId}/history considered as totally separate paths with nothing in common even path parameters. Moreover, you can't define global parameters.
I propose to allow for recursive paths, it would look like that:

paths:
  '/':
    parameters:
        - in: query
          name: globalParam
          type: string
    '/user/{userId}/':
       parameters:
          - in: path
            name: userId
            type: string
       get:
           #....
       '/history':
          get:
             #...

Pros:

  • non-breaking change, you can still define old style with /user/{userId}/ and /user/{userId}/history as separate paths.
  • allow for global parameters similar to #633, but without breaking change and JSON pointer stay nice and short #/parameters/<name>.
  • remove duplication for path parameters
  • at least party address @webron concern about adding description into pathObject see https://github.com/OAI/OpenAPI-Specification/pull/632#issuecomment-208094651
  • doesn't conflict with possible extensions to path template mechanism, since recursive paths just concatenate.
  • if things like consume, produce, responses will be added into pathObject, remove a lot of duplication.
  • Easy to implement validation in JSON Schema using patternProperties.

Cons:

  • force tooling to process recursion and parameter merging

Most helpful comment

It's not an argument, just thing to note.
Such functionality supported in WADL, Google Discovery, I/O Docs, RAML and probably other formats.
So it looks like industry-wide practice, so it worth to consider.

But I don't say OpenAPI should automatically borrow from other formats, especially from WADL.

All 14 comments

I think this abuses the path key too much. Better to keep at top-level, or at path item level.

I think this abuses the path key too much. Better to keep at top-level, or at path item level.

@fehguy Can you please elaborate.
Do you concern with human-readability of spec?
Or support in tooling ?

yes to all. It's an overload of a path name (is parameters a legal path?), is weird to read, and will cause tooling hassles. Suggest using top-level, parameters, or path-item level to accomplish a nearly identical goal.

@fehguy

is parameters a legal path?

It's easy, only keys what starts with / is paths.

will cause tooling hassles

I agree with this one. It requires tool author to write additional 50-100 SLOC.

It's not an argument, just thing to note.
Such functionality supported in WADL, Google Discovery, I/O Docs, RAML and probably other formats.
So it looks like industry-wide practice, so it worth to consider.

But I don't say OpenAPI should automatically borrow from other formats, especially from WADL.

@IvanGoncharov I think it is a fairly fundamental difference in the way APIs are described. Admittedly paths are naturally hierarchical, and getting the reuse ability for free is nice. However, it doesn't help when it comes to re-use of query parameter descriptions. Personally I find deep paths are often a design smell in APIs and I'm not sure we should be encouraging them. If other design formats support that style of API description and you find that more natural, then take advantage of it. I'm not sure the goal should be to make all API description languages work the same way.

This can lead to some nasty structures too - potentially describing the entire API as one big deeply nested tree. Putting aside the issues it may cause tools, it would be harder for human-readability as well.

This also potentially puts us back to 1.2 and earlier versions with the organization concept of resources. One of the goals of moving to tags for grouping was to allow the flexibility there.

I don't find the benefits enough, especially with the supported reusability.

I'm not sure the goal should be to make all API description languages work the same way.

Totally agree, it's part of the evolutionary process.
But I think common practices should be evaluated for possible accepting into OpenAPI.

This can lead to some nasty structures too - potentially describing the entire API as one big deeply nested tree.

I see that hierarchical structures in JSON/YAMl are a question of personal taste.
Personally, I agree with @darrelmiller:

Admittedly paths are naturally hierarchical

But I don't want to turn this into some kind of bike-shed discussion.
If someone will have any technical concerns I would be happy to address them.

My proposal is to leave this issue open for few weeks to maybe have some feedback from the community.
And then make official technical committee decision about it.

From a human factors perspective, nesting is normally the preferred structure. Originally, that was what I preferred about RAML over Swagger. But with OAI, the content is verbose enough that nesting does not help - there is too much info to fit nicely into a single screen unless the tools to a really good job with collapsing sections. Constantly expanding/collapsing gets pretty tedious.

I agree reusing parameters is useful and a desired feature. One must be careful with adopting nesting because you to clarify exactly what is inherited from the parent. All parameters with in: path? I suppose. less likely for parameters with other values for in, and then you may need a way to override an inherited parameter, which adds complexity. What else do we gain by nesting? I can't think of much else.

(We actually have an internal tool that we're integrating into our Swagger editor which can add a missing path parameter by finding a matching in: path parameter via other paths.)

Looking outside API descriptions, I think this is somewhat analogous to object modeling in OO languages. Inheritance was cool, but then it got abused, and composition became a preferred way to model things. Languages which only support single inheritance are less powerful/expressive than those that allow composition/mixins/traits. Nesting paths feels analogous to OO inheritance.

See also #445 for an alternative to nesting -- use parameter sets.

I too think this should be part of the spec. Surprised its not.
Replicating common sense shouldn't be something to discuss or argue about.

This looks to me like a very useful feature, and i'm not sure why it was closed. Is it abandoned ?

Anyway, allow me to expose a legitimate usecase that only this nesting feature would fulfill (as fas as I understand): service composition. I'd happy to know if there's another way to implement it.

Let's say we have two independent services, A and B, each coming with their respective service descriptions serviceA.yaml, serviceB.yaml embedded at their roots.
These services can potentially be deployed as standalone applications, on arbitrary URL subpaths, e.g. http://foo.com/serviceA, with its description then sitting at http://foo.com/serviceA/serviceA.yaml and looking like

servers:
  - description: Service A
    url: .
paths:
    ...

Then there's a need to deploy a service C, that composes A and B under two subpaths :
http://foo.com/serviceC/serviceA and http://foo.com/serviceC/serviceB.
It should be possible to declare this composition in http://foo.com/serviceC/serviceC.yaml, containing something like :

servers:
  - description: Composed Service C
    url: .
paths:
  /serviceA:
    $ref: 'serviceA/serviceA.yaml'
  /serviceB:
    $ref: 'serviceB/serviceB.yaml'

Can you comment on this usecase ?

@pduchesne I'm pretty sure your use case is different from the original use case in the issue.

The issue was about being able to nest path descriptions under each other _to arbitrary depths_ to factor out common path prefixes. You are just combining paths from two sources, but at the same level (your end result is equivalent to manually copying everything from A's paths: and everything from B's paths: under C's paths:, where C's prefix of http://foo.com/serviceC can be set by the normal OAS base path functionality).

yes, I understand that the original issue is about potentially arbitrary deep nesting, while my example is about factoring out the first level of the path.
However, I still don't see how, with the current spec, I can express the fact that I want to import all paths elements from serviceA under a subpath in serviceC, and all path elements from serviceB under another subpath. In my understanding, being able to factor out subpaths serviceA and serviceB to import a set of paths elements under them is one way to solve it.
If you think this is feasible, can you elaborate on how you would do this ?

@pduchesne if you have a new question different from the one raised in this issue, you should open a new issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nomadtechie picture nomadtechie  路  4Comments

slinkydeveloper picture slinkydeveloper  路  4Comments

niquola picture niquola  路  5Comments

andy-maier picture andy-maier  路  4Comments

Prasanthmv picture Prasanthmv  路  4Comments