Allow documenting HATEOAS APIs (pathless operation / interface / URI class / operation type)
See original GitHub issueTLDR
(added after some discussion)
- “interfaces” (like path items, just without path parameters, and not linked to a path template)
- a path item can refer to an interface (which is implemented), possibly adding path parameters to it
- a string property (containing an URI) in a schema can refer to an interface (which means the consumer can know which operations can be used on this URI)
Background / Current Situation
I work at a company where our Restful API Guidelines prescribe both “document your API using OpenAPI” and “Use HATEOAS” (“Hypertext as the Engine of Application State”, one of the core principles of REST).
Unfortunately both do not work together nicely:
- Swagger/OpenAPI 2.0’s model is “we have paths which can be distinguished in some way, and describe the operations on those paths” (including their data format).
- The HATEOAS model is “The client gets a result which might contain links to other resources, and can decide to follow them, no matter which URI format they have”.
Currently the intersection between both is “have links in your result, but just to URIs which are also described as paths in your Swagger definition, and describe in descriptions what kind of URIs you can expect”.
Ideas
A core point of HATEOAS are media types and link relations. An API definition should mainly be a description of the media types and what operations they imply for links included in them. (Paraphrased from a blogpost of Roy Fielding.)
Media type definitions are analogous to what OpenAPI’s definitions
are currently, might even be an extension of that. For models with a property of type string
, format uri
we can then additionally refer to the URI class of that URI.
A URI class is defined analogously to the current path definitions, but with some name to be used in model definitions. The URI class defines what operations are possible on an URI, which parameters are allowed/needed (no path parameters, I guess), and what can be expected in return. (The URI class is not a property of the URI itself, but of its usage in a specific place. The same URI could appear with multiple URI classes.)
I’m not yet sure how link relations can come into this – I guess we might need a way to define the URI class depending on link relation or similar.
A client needs just some initial “bookmark URI” (so a single path definition might be fine), and then can take a link (with a given URI class) and use the operation behind the URI class to do what it wants to do. The format of the second URI doesn’t matter anymore to the client – it can even have a different domain name than the bookmark one. But still everything can be strongly typed if wanted.
Issue Analytics
- State:
- Created 8 years ago
- Reactions:49
- Comments:72 (50 by maintainers)
Top GitHub Comments
The use of x-interfaces / x-interface in #576 seems to solve a different problem (that of several APIs or API subresources implementing an API contract/interface/pattern.)
I’m more interested in the OP question of defining and documenting an API via HATEOAS. We’d like to hide the paths in the API (i.e. in the UI) and encourage clients to consume links rather that hard-code the API to fixed paths. (The paths become more of an implementation detail. They still exist and could be revealed in the UI for reference / lookup, or presented in an alternate view.)
Thus, an API starts at the root and the client can discover the set of links to nested resources via compound keys that include a link relation (name), a verb (PUT, POST, etc.), a type (request and/or response media type), and a description. The definition of a link may also include a path but that is more of an implementation attribute. Thus, each path in an OAS can be associated with one or more contained resources
For example if the API has two primary resources,
models
andactivities
, the root would containSo from the root, one can find models and activities (as resources), and also discover how to create activities, and from the collection, one can access an individual model. From a model, there are links for operations on that model (the uri is inherited from the current path context).
The UI could then navigate the API by exploring links (hiding the URI by default).
I’ve published a blog post on the OHM format : https://dev.to/cbornet/ohm-the-mediatype-for-rest-hateoas-powered-by-openapi-2aba . Happy to get your feedback on it !