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

Consider hypermedia for resource listing #97

Closed
rgarcia opened this issue Jan 2, 2013 · 8 comments
Closed

Consider hypermedia for resource listing #97

rgarcia opened this issue Jan 2, 2013 · 8 comments
Labels
Milestone

Comments

@rgarcia
Copy link

rgarcia commented Jan 2, 2013

A couple of thoughts on swagger and making it a little more hypermedia friendly:

  • HTTP OPTIONS on "" gives all possible URI templates supported by the server via the HTTP Link header. From the spec: 'If the Request-URI is an asterisk (""), the OPTIONS request is intended to apply to the server in general rather than to a specific resource.' Example using the Wordnik API:
Request:
OPTIONS *

Response Headers:
Link: </words.json/search/{query}>; method="get"; title="Searches words">,
      </words.json/wordOfTheDay>; method="get"; title="Returns specific word of the day",
      etc.

The top-level API documentation (swagger-ui) can group these links however it likes.
NOTE: the "method" attribute and use of URI templates are both (reasonable, IMO) departures from the HTTP Link header spec.

  • The body for an OPTIONS request provides a subset of the swagger info for the URI template requested:
Request:
OPTIONS /words.json/search/{query}

Response:
Allow: GET
Content-type: application/json
Body:
{
  "operations": [{
    "summary": "Searches words",
    "httpMethod": "GET",
    "errorResponses": [{
      "reason": "Invalid query supplied.",
      "code": 400
    }],
    "nickname": "searchWords",
    "responseClass": "wordSearchResults"
    "parameters": [{
      "name": "allowRegex",
      "defaultValue": "false",
      "description": "Search term is a Regular Expression",
      "required": false,
      "allowableValues": {
        "valueType": "LIST",
        "values": ["true", "false"],
        "valueType": "LIST"
      },
      "dataType": "string",
      "allowMultiple": false,
      "paramType": "query"
    },
    etc.
    ]
  }]
}
@jedahan
Copy link

jedahan commented Jan 16, 2013

Looks well thought out, certainly would like to see this.

@dfeist
Copy link

dfeist commented Apr 11, 2013

Related discussion here: https://groups.google.com/forum/#!topic/swagger-swaggersocket/Xd5cWuTusVs

In summary, initially I was proposing a mediaType based approach for obtaining swagger metadata from resource uri's rather than needing to expose metadata via different (inconsistent uri's). But after reviewing this issue, and taking a closer look at the HTTP Spec, I believe this is the way to go (using OPTIONS).

In my mind the body should be returning the swagger meta-data (ideally with a custom media-type, even if Accept header is vanilla json). This approach can be used consistently for both baseUri (resource listing) and for specific resources). To retrieve resource listing my interpretation is that the best approach is the use of OPTIONS on the baseUri "/" or "/api" or whatever it is, not "OPTIONS *" which is a server-level command. It maybe that I'm exposing multiple api's on the same server http://www.shop.com/providerAPI, http://www.shop.com/customerAPI.

The only challenge in implementing this new approach is the need to update client support; both UI and code generators need to be able to:
i) discover resource listing from a baseUri (using OPTIONS {baseUri} rather than GET {baseUri}/resources.json
ii) obtain api declaration using resource uri in resource listing via OPTIONS method.
(and work out a way to fallback to current approach)


Another somewhat related issue is that of nested resources. Given the following resources

{baseUri}/a/
{baseUri}/a/b/
{baseUri}/a/b/c/
{baseUri}/z/

  • OPTIONS requests for all of these uri's should result in a api declaration document being returned as body.
  • OPTIONS request for {baseUri}/a currently returns api declaration that documents this resource and all nested resources. Ideally meta-data for {baseUri}/a links to metadata of nested resources rather than nesting everything in the same json.

@pose
Copy link

pose commented Apr 14, 2013

I don't think using OPTIONS is a wise idea. If using CORS for the preflight request, that request body will return the Swagger resource description? Wouldn't that make the implementation of CORS capabilities in a swagger enabled rest API problematic?

@dfeist
Copy link

dfeist commented Apr 15, 2013

It is important, and very valuable, for ReST resources to be self-describing. In order to do this either the resource needs to reference it's metadata (via a header maybe), OR the metadata needs to be accessible via a standard or documented mechanism (http method, header, mediaType or separate uri).

URI
The use of a separate uri/path is not only not ReSTful because you are defining a new resource to document a resource, but unpractical due to possible conflicts etc. Also because a different uri is needed it relies on a standard being defined and documented as to where to find this metadata. Swagger hasn't defined this because it's not practical to as Tony said "The reason there isn't a standard location is because it's hard to claim the path of resources.json or api-docs.json"

Header/MediaType
A special header could be used (X-Resource-MetaData) to request metadata or a metadata specific representation (application/swagger+json) requested. The issue with this approach is that you are using 'GET' and therefore should really be returning a resource representation and not hijacking it for something else. Also this approach can cause problems with things like API throttling because otherwise you'd need to throttle GET requests based on a header, not nice!

OPTIONS method
This is the approach envisioned within the http spec where the OPTIONS method is used to obtain information about a resource without implying a resource action (this helps with things like throttling). This approach while isn't widely adopted is generally accepted as the correct way to expose resource metadata. I understand that CORS also uses OPTIONS, but I don't see that this conflicts in any way. Both the CORS headers returned and the resource metadata describes the resource. Optimisations can easily be made to not return the response body if it is clear from the "Origen" request header that it is a CORS pre-flight request.

@glennblock
Copy link

One way to address this could be to use profiles (http://tools.ietf.org/html/rfc6906). You can return a Link header with a profile link relation type OR if you have a custom media type bake in profile as part of the definition. The href of the profile can then point to a document of any format really for describing the format. It's not violating any REST constraints as profile is discoverable.

@glennblock
Copy link

@rgarcia for Options the spec states that "*" is only useful for a ping or no-op method.

"Since a server's communication options typically depend on the resource, the "*" request is only useful as a "ping" or "no-op" type of method;"

Seems like a stretch to use it for high level server-level metadata and not something expected.

@glennblock
Copy link

I would vote much more toward embedding links in a response rather than requiring a user to know they do an Options. It's much more explicit and IMO in the spirit of hypermedia.

@fehguy
Copy link
Contributor

fehguy commented Aug 30, 2014

closing as not per design

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

No branches or pull requests

6 participants