Closed LukasRos closed 5 months ago
From a spec perspective, the JSON pointer with a * is not valid. While defining the links capability there was no attempt to define a mechanism to that would declare a set of links based on the assumption that a response contains a set of similarly structured objects and a client is likely to select one of those objects.
This scenario is definitely something that I have done using explicit hypermedia, but I'm not sure how feasible it would be the static links design in OpenApi V3. JSON pointer doesn't support returning a set of nodes. But JSONPath does. However, even once we are able to reference the set of potential parameter values, we still need a way to parameterize it to be able to select a particular parameter instance.
It's an interesting idea and one worth exploring more, but we need a way to indicate that a link parameter requires further client input before being resolvable.
Ok, thanks for your quick reply and the clarification, so I've understood links are always 1:1 pointers to other operations, never 1:n. I think that 1:n links with variables are a really interesting feature and would love to see them in a future version of the OAS.
We also have the "get (filtered) collection/get single item within collection" pattern in almost all of our APIs, and it would be helpful to link the operations in that pair in a machine-readable way beyond naming or URL conventions.
I may annoy @darrelmiller by jumping in with this, but JSON Hyper-Schema can express this sort of thing as of draft-06, and better in the soon-to-be-published draft-07.
Of course, nothing implements recent hyper-schema drafts, it will be some time before I put out a reference implementation, and it doesn't have anything remotely resembling the ecosystem of OpenAPI. But... if anyone's looking for ideas, we've at least thought about this issue a lot.
In #1452, I suggested JSONPath, which solves the same "identify pattern of things" problem. The advantage is that it should feel familiar to XPath users, so it should be too offensive to those dealing with XML data.
The challenge with JSONPath is there is no detailed specification to ensure consistent implementations.
@tgockel @darrelmiller in Hyper-Schema, we avoided JSON Path by attaching links at specific locations within the schema (mapping to corresponding instance locations). So attaching the link under an items
makes for a link attached to each element of the instance array that items
describes.
Then we used Relative JSON Pointer to adjust variable resolution upwards or downwards. This is simple and unambiguous.
With JSONPath, in addition to the lack of specification, wildcarding really returns sets of data, and then you have to correlate your "current" location with the location within that set. Which is solvable but increasingly complex the more deeply you nest things.
Relative JSON Pointer solves this by starting from the most specifically nested thing, so that going "down" from that point does not require wildcarding, while going "up" keeps you in the correct subtree without having to calculate things.
It's a really complicated problem involving being able to set the attachment point of the link and independently set its context to potentially a different location than the attachment point, and independently set the resolution starting point of every template variable. And handle cases where the location you want to resolve from doesn't exist. We basically spent a year on this spread out across draft-06 and draft-07.
An example of different attachment point vs context is the "item" link relation, where it needs to be attached to the individual array items, but the context is supposed to be the entire collection, not the single array element within the collection.
I was idly wondering if we could resolve one simple case of this issue with some guidance in the specification:
If the link parameter expression resolves to an array, and the target parameter is itself not an array, then any item(s) from the source array MAY be used to provide the target operation parameter value.
This would handle the case of a simple array of resource id
s, but not an array of resources containing id
s (this could be accommodated by providing an additional itemExpression
- but that's getting messy) . I appreciate that a more generic solution would be infinitely preferable.
The wording above is just to get a feel for the idea.
@MikeRalphson That is a decent solution for expanding an array of ids into an array of links. I fear the much more common case is the array of objects where each object has an Id.
It will be interesting to see if we get alternateSchema
working if a hyper-schema could be used to achieve this goal.
@darrelmiller
It will be interesting to see if we get alternateSchema working if a hyper-schema could be used to achieve this goal.
I think this will be possible. I'll keep this use case in mind.
Any progress welcome. Here a 1:1 pet sample as a first contribution:
# Link pets -> pets{petId}
# -----------------------------------------------------
links:
ShowPetByPetId: # <---- arbitrary name for the link
operationId: showPetById
# or
# operationRef: '#/paths/~1pets~1{petId}/get'
parameters:
petId: '$response.body#/0/id'
description: >
The `id` value returned in the response can be used as
the `petId` parameter in `GET /pets/{petId}`.
Currently, the spec defines links
property only in Response Object
(links
in Components Object
do not help with this issue).
Would it be possible to add links
property to Schema Object
as well?
The $response.body#<non-negative-integer><JSON pointer>
in this context would be resolved relative to each schema object instance in the response, yielding a link.
This way, getUserDetails
operation simply returns an array of User
schema objects which define the links
derived from each instance. The client gets the array of links resolving the User
schema object links
relative to each instance received in the response.
My understanding is that x-links
can already be used with this semantics in Schema Object
because it allows for Specification Extensions
.
JSON pointers in this context would be resolved relative to each schema object
The JSON Pointer spec says,
Evaluation of a JSON Pointer begins with a reference to the root value of a JSON document
https://tools.ietf.org/html/rfc6901#section-4
We would have to redefine JSON pointers and the way fragment identifiers work to make this happen. I would recommend using JSON Hyperschema if you need to do this.... or actually do hypermedia.
I guess the use of hypermedia is not in line with OAS design-time Link Object
as it requires link information in the runtime response. What I had in mind is something similar to JSON Hyper-Schema and relative JSON pointers, as described by @handrews in his comment on Jan 5, 2018, but without needing separate hyper-schema resources. Ideally, all links would be included in the OAS API spec.
As explained in Relative JSON Pointer, section 6, the fragment identifiers do not apply to relative pointers.
Would it be possible to have links
in OAS Schema Object
, allowing for the <non-negative-integer>
prefix of JSON pointers (i.e. using Relative JSON pointers) as part of the standard OAS spec?
As far as I am aware, the only changes needed in the OAS are:
a) Add links
as a regular property of Schema Object
(same as in Response Object
)
b) In Runtime Expressions, redefine the fragment
:
fragment = a JSON Pointer [RFC 6901](https://tools.ietf.org/html/rfc6901)
by allowing for the optional non-negative-integer
prefix, having semantics explained in Relative JSON Pointer:
fragment = [ <non-negative-integer> ] <a JSON Pointer [RFC 6901](https://tools.ietf.org/html/rfc6901)>
This is a backward-compatible change.
If <non-negative-integer>
is not there, JSON Pointer is absolute. If present, JSON pointer is relative.
In majority of use cases, the evaluation of links does not depend on context in which a Schema Object is found, but rather on a Schema Object property (e.g. the unique id
). Therefore, in a simplified client implementation, it should be sufficient to support evaluating only relative JSON pointers starting with zero, i.e. having the <non-negative-integer>
set to zero.
Has this been considered further since last year?
I have a model whereby an entity "A" that is related to one or more entities of type "B".
The entity of type "A" has a response body that returns an array of ID strings for entities of type "B".
For HATEOAS, I need to provide links to the "get entity B" operation by each individual ID from this array. I cannot find anyway to define this in OAS3 ... but then again I am a newbie :-)
@xorcus stated:
I guess the use of hypermedia is not in line with OAS design-time Link Object as it requires link information in the runtime response.
Does this mean that we cannot model what I think is pretty standard HATEOAS using the links object?
Hi everyone!
Any progress on this? Considering OpenAPI schemas can be used by tools like graphql-mesh
to generate & run GraphQL APIs, links
missing this feature is an obstacle to automatically handle nested resolvers. Let's say you have a query like:
query {
pets {
name
owner {
name
}
}
In the GET /pets
response, you can't describe the pet => owner
relation with a link like:
links:
getOwnerById:
description: Returns the owner of the pet
operation: getUser
parameters:
userId: '$response.body#/{index}/ownerId’
This would be a huge and welcomed improvement!
Sorry for the duplicate post. But at least there is an additional example of what is needed here: Example for link with parameter serialization needed #2539
So what could be done and who could do anything to get a step further to a solution as proposed by xorcus or hrougier? I am asking as e.g. UN/CEFACT found OpenAPI to be very relevant and so a lot of EDI-minded organizations currently start looking into the OAS. And here a link feature like this is really needed...
@AP-G Interesting to have the connection with the EDI community!
This scale of change is best discussed in Moonwalk (and can be backported if relevant and we decide to keep the 3.x line going). Closing in favor of:
The OpenAPI v3 links feature allows specifying related operations. To me, however, the spec was not clear on whether it's possible and if, how to define links that require an additional variable for the call.
To give a practical example, assume there's a GET
/users
operation to list all users and a GET/users/{id}
operation to get details about an individual user. I could add the latter as a link to the former but this link requires an additional piece of information, specifically which user from the list I want to receive details for.Is that possible or even desired to express with the links feature? If yes, is
*
the right syntax for a placeholder in JSON pointer? If not, is there another way?