Closed jonathann92 closed 4 months ago
This currently isn't possible. Link Parameter keys are just parameter name references, not expressions. This is an interesting enhancement. I'm not sure exactly how many people would use it, nor what the challenges are to implement it.
I think that maybe the right way to implement this, would be to add a new parameter type that could use expressions as a target.
openapi: 3.0.0
info:
title: Experiment
version: 1.0
paths:
'/':
get:
responses:
'200':
description: ok
links:
submitLink:
operationId: postSubmit
parameters:
foo: request.body.foo
'submit':
post:
operationId: postSubmit
parameters:
- name: foo
in: expression
target: request.body.foo
Although, having said, this. I'm really not sure how a client would construct the rest of the requestBody. Feels a bit weird to me.
thanks for replying quickly! I just checked my .yml sample and I forgot I removed the update pet section. I added the update pet api endpoint in the .yml file.
I find if we can take data coming back from responses like a pet id and pet category id would be helpful to make workflows for an api. Maybe we can format it something like in my example file. We would assign the schema property to the value in the response.body.id and then the rest of the schema stays as their default values
Any update on this? I'm also in need of the use case explained by @jonathann92. Currently, links are not usuable for operations with several properties in the target request body. It feels like the most common use case in this scenario is setting just certain properties in the target request body.
I don't understand what the purpose of using a link to a single property to set an entire request body is. If your request body only has one property in it, then why would it be a request body and not a parameter in the first place?
I get that you can instead link an entire response to an entire request body, but it's REALLY hard to design an API in a symmetric way like this. More often, you have some properties in one operation's response that correspond to some properties in another operation's request body. The current "all or nothing" support for linking to request bodies seems rather obscure and impractical.
It would be much more useful to follow the same structure of the existing implementation of parameters
links, for setting only certain properties in a request body. I think there's a simpler way to do it rather than the suggestion made by @darrelmiller. Like this:
links:
getInventory:
operationId: getInventory
requestBody:
id: '$response.body#/id'
The last line maps the property id
(in the target request body) to the property id
(from the source response). This way, the key is used in the exact same way it's currently used for the parameters
keyword.
Is there a reason it wasn't implemented this way originally? This standardizes the syntax for parameters
and requestBody
keywords. Setting only certain fields in a target request body is the common use case. Setting an entire request body is the edge case. The implementation and syntax should cater to the former.
@darrelmiller any update on this topic? (see :point_up: )
I agree with others above, the current requestBody
option of Link object is not useful in most cases.
Thinking this through...
The requestBody
schema of the link target may be an object or a list. So we need to use a JSON Pointer to address the linked fields in it. A JSON Pointer can address into nested objects, or "first item of a list" etc, all potentially necessary here. A runtime-expression provides this feature, via the fragment portion.
So I think @darrelmiller's proposal is the best idea:
parameters:
- name: foo
in: expression
target: $request.body#/foo
But not all runtime-expressions would be valid, since we can only target elements of the request, so an expression like $response.body#/status
would be meaningless in this context. Since we already have good options for parameters in other parts of the request, maybe we actually just want this:
parameters:
- name: foo
in: body
target: /foo
Now the target
is just a bare JSON Pointer, rather than a runtime-expression.
One other thing we need to consider is what to do about the style
field of the Parameter object. It seems like we should just omit it, along with schema
, explode
and allowReserved
since they are not relevant - we want to use the schema and serialization style already defined for the request body. It should be invalid to specify any of these fields in conjunction with in: body
.
So a full example would look like:
openapi: 3.0.0
info:
title: Experiment
version: 1.0
paths:
'/':
get:
responses:
'200':
description: ok
links:
submitLink:
operationId: postSubmit
parameters:
foo_param: $response.body#/foo_val
'/submit':
post:
operationId: postSubmit
parameters:
- name: foo_param
in: body
target: /foo
Meaning:
_"take the foo_val
value from GET / [200]
response and use it as foo
in request body to POST /submit
"_
It does not matter if the postSubmit
request schema has other required fields which we don't specify as parameters, it just means that they cannot be sourced from the linked request. The client may ask a user to fill them out manually, or in my use case (automated testing) I will generate fake data that matches the schema for those, while extracting foo_val
from the previous request.
I can think of one other alternative construction, which doesn't use the parameters
section and is defined within the Link object only. I'll probably be using this in the interim, since I can define it as an extension property:
openapi: 3.0.0
info:
title: Experiment
version: 1.0
paths:
'/':
get:
responses:
'200':
description: ok
links:
submitLink:
operationId: postSubmit
x-requestBodyParameters:
/foo: $response.body#/foo
'/submit':
post:
operationId: postSubmit
Where the key /foo
is a JSON Pointer into the requestBody
of the link target, and the value $response.body#/foo
is a runtime-expression to extract a value from the current operation.
One advantage of this link-driven format is if you are linking to an operation in a schema that you don't control. The author of the other schema may not be aware of which body fields need to be exposed as parameters in order for you to make a successful link, but it doesn't matter here as we can specify everything we need to as the link author.
I've recently encountered this same problem. Based on the above discussion and my own experience, I think this is not an uncommon use case for links and we should find some way to broaden the definition of links to support it.
FWIW I favour the x-requestBodyParameters
form described above, defined as part of Link
object, as this fits naturally when defining the equivalent for "backlinks" as discussed in #2196
Otherwise people might wonder what is the point of defining request body fields again as parameters
since it would seem obvious that all fields in the request body schema are already a type of parameter.
So the use-case for this feature is specifically around defining Links, how to specify that values from the response of one operation should be used in the request body of a downstream operation.
After applying OAS extensively towards many different applications, like AWS API Gateway, client generation, documentation, design, and many other things, I MUST request that this be brought to the forefront of discussion for the TSC.
Of the many proposals around this topic, any would do. I don't think the problem is the how, it's the why. Therefore rather than being noise amongst the other great proposals on this thread, I will advocate for why this is a paramount need for OAS.
Every set of backend services, whether micro or monolithic, has operations dependent upon responses from the others. It's almost safe to say, that for documentation purposes, if there are no fragments of a request body that aren't from another operation's response body, the two requests don't belong in the same spec because they'd have nothing to do with each other.
It's a common process for any type of modeling tool to granularly define relationships. Whether it be an ERD or a Function Call Graph, there needs to be a way for description.
Further, it's often ambiguous whether identically named parameters are in fact the same or sourced from other responses without explicit declaration. For one to make assumptions about parameters based off name in a large OAS inevitably leads to bugs.
Hardly ever do entire request bodies comprise of a singular response attribute. In fact, if this were the case, one could argue that it's almost certainly flawed API Design. If an entire request body is to be sourced from a response body, why wouldn't the original operation that returned said response not just make the request on the client's behalf? The current implementation of having: responseBody
encourages an anti pattern, and goes against modern paradigms. Should a developer who doesn't know better try to design an API completely using OAS, they might be mislead.
The OAS and what it aims to do are truly something great. Using OAS it's possible to document web request for both the human and machine. One of the last things missing is the ability to further describe the relationships each operation might play into another. Should this "last mile" problem be solved, developers integrating with API's might not ever need to even write a line of code nor converse with it's maintainers.
@darrelmiller, @whitlockjc, @earth2marsh, @MikeRalphson, @webron, @usarid, Please do consider/reconsider this enhancement during your next TSC.
++ on what @luckybroman5 says here.
I agree with the general sentiment here but I'm having trouble following some of the details. For example:
Further, it's often ambiguous whether identically named parameters are in fact the same or sourced from other responses without explicit declaration.
A Link Object
specifies an operationId (required) and then parameters. The named parameters in the link are parameters of the operation with that operationId, which must be unique according to the spec. So I see no potential for ambiguity there.
But the details are not really important, since there are clear cases for links to request body properties -- and some other changes/improvements to links (e.g. "back links"). The TSC has been consumed recently with the monumental effort of getting OpenAPI 3.1 out the door. Now that that is done I think they will be open for "new business". I'll work to get this on the agenda for an upcoming meeting.
I'm glad to hear this is being considered. If I can clarify anything from my previous comments and suggestions please let me know.
As with the backlinks I've currently implemented this for my purposes using extension properties, documented here: https://apigraph.readthedocs.io/en/latest/reference/openapi-extensions.html#x-apigraph-requestbodyparameters
I agree with the general sentiment here but I'm having trouble following some of the details. For example:
Further, it's often ambiguous whether identically named parameters are in fact the same or sourced from other responses without explicit declaration.
A
Link Object
specifies an operationId (required) and then parameters. The named parameters in the link are parameters of the operation with that operationId, which must be unique according to the spec. So I see no potential for ambiguity there.But the details are not really important, since there are clear cases for links to request body properties -- and some other changes/improvements to links (e.g. "back links"). The TSC has been consumed recently with the monumental effort of getting OpenAPI 3.1 out the door. Now that that is done I think they will be open for "new business". I'll work to get this on the agenda for an upcoming meeting.
Hey @mkistler, apologies for the misunderstanding. I'm only talking about the inability to link request attribute in a body back to response attribute. Since one is limited here, unless explicitly stated, it's ambiguous of where that request attribute in the body is sourced.
That being said, I really appreciate your consideration for this. I have used the OAS quite a lot throughout my career and am thankful of how great it is.
+1 on getting this on prioritized!
Any progress on this?
Like the OP I need to decorate the swagger doc with information that links data from the response of a GET request to a specific property of a JSON object request body used in a POST request.
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:
Hi,
I would like to use links to set certain fields in the request body of another operation. For example using the petstore example, I would like to create a pet and grab the pet id from the response. Then I would like that pet id to be reflected in the request body for the "PUT" pet method to update the pet.
I've seen examples of links where they take the value from the response and put it into another request's header, query, path parameters. However I am not sure how to use the setting values in the requestBody correctly. On the links/requestBody documentation website there is an example but it sets the request body like this, "requestBody: '$response.body#/id'". From my understanding, this would make the entire requestBody the id in plaintext instead of a xml or json object.
How would I set the requestBody's id to "$response.body#/id"?
I also see on the swagger.io website saying that we can prefix parameters.
Would it be possible to do prefix with the requestBody like this: parameters: requestBody.id: '$response.body#/id'
I made a .yml file in case you wanted to see what I am trying to achieve. You can get the link to the raw file and explore it on the petstore swagger
Links: Sample links .yml file: https://github.com/jonathann92/PlainFiles/blob/master/openapi.yml#L174 Petstore swagger: http://petstore.swagger.io/ Documentation for links: https://swagger.io/docs/specification/links/#requestBody