Open Kostadin-Ivanov opened 9 months ago
I'm pretty sure it works by just passing
requestBody ="MyItem"
the string being interpreted as a ref (whether or not it is actually defined)
If I pass
requestBody = "MyItem"
I get error: **File "c:\workspace\.venv\Lib\site-packages\apispec\core.py", line 352, in _resolve_refs_in_request_body for media_type in request_body["content"].values():
TypeError: string indices must be integers, not 'str'**
From this code:
**def _resolve_refs_in_request_body(self, request_body) -> None:
# requestBody is OpenAPI v3+
for media_type in request_body["content"].values():
self._resolve_schema(media_type)
self._resolve_examples(media_type)**
which is from the **.venv\Lib\site-packages\apispec\core.py**
Sorry, i tried to add a screenshot but did not work for some reason.
I tracked the usage of: **_resolve_refs_in_request_body** and it is called by: **_resolve_refs_in_operation**, which is called by: **resolve_refs_in_path**, which then is called by the path() function, which is called by my code with: apiSpec.path(...) in the description of this ticket.
In other words, the flow is:
**
apiSpec.path(...)
-> resolve_refs_in_path
--> _resolve_refs_in_operation
---> _resolve_refs_in_request_body**
where the _resolve_refs_in_request_body is handling the passed "MyItem" string as dict and throws the above error.
Sorry, please try
requestBody = {
"content": {"application/json": {"schema": "MyItem"}}
}
as in this test.
Thank you, Jerome.
This example works fine, but my question was if could set it more like:
requestBody = "#/components/requestBodies/MyItem"
or
requestBody = { "$ref": "#/components/requestBodies/MyItem" }
which will then result in: post: description: Create MyItem operationId: createMyItem requestBody: $ref: "#/components/requestBodies/MyItem"
I'm afraid the content type (application/json
) must be specified by the user.
The fact that you don't need to pass the components/requestBody
part is nice, though.
Thank you Jerome.
so, for the moment the requestBody needs to be setup with its schema definition like: { content: application/json: schema: ... }
Thank you for your support on this and hopefully, the _resolve_refs_in_request_body function, and others similar to it, might be updated in such way that to handle exact schema parameters, like the one above and $ref like { "$ref": "#/components/requestBodies/MyItem" }
.
I guess that you can close this ticket as "replied" :)
Thank you and have a great day.
I'm not sure I get it. You need to pass the content type because apispec can't guess this is JSON. In flask-smorest, for instance, things are more automatic because we define a default content type.
I don't see the point of passing the full component path, I think it is nice that apispec does that for you and you only need to pass the component name. If using marshmallow plugin, you may also pass the schema object and apispec resolves it for you.
Sorry, I misunderstood you.
Your example:
requestBody = {
"content": {"application/json": {"schema": "MyItem"}}
}
worked. However, it still added some kind of duplication in my generated OpenApi under each of my generated operations like:
post:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/MyItem'
put:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/MyItem'
in my generated OpenAPI file, where I am looking to get more like:
post:
requestBody:
$ref: '#/components/requestBodies/MyItem'
put:
requestBody:
$ref: '#/components/requestBodies/MyItem'
where the $ref is pointing to a pre-defined request body schema like the one below:
components:
requestBodies:
MyItem:
content:
application/json:
schema:
$ref: '#/components/schemas/MyItem'
Anyway, for the moment it does not seem to be achievable with this
requestBody = { "content": {"application/json": {"schema": "MyItem"}}}
approach.
I will follow your example and see if I can find some other way to save 3 lines of text under each operation :)
Thank you again and have a great day :)
I didn't check but I'm not sure what you're trying to achieve is valid OpenAPI. You may want to double-check.
I wouldn't worry about the duplication in the generated spec file. However, code factoring is nice. You could define a function to add the content type for you. Or use a wrapper such as flask-smorest that does that and more.
The swagger editor accepts the components:requestBodies:...
It is not perfect example, but here is one, of "MyItem". my_item_example_openapi.json
Works fine on SWAGGER editor.
Thank you very much for your time and help on this question :)
You're totally right. I got confused. Sorry about that.
The example I picked from the tests resolves the schema in the request body, not the request body itself.
What you're trying to achieve is absolutely correct and in fact desirable.
It should work with
requestBody ="MyItem"
but this is apparently not implemented.
What would need to be done:
"request_body": "requestBodies",
to utils.COMPONENT_SUBSECTIONS
.
Add a Components.request_body
method to register request bodies in components section.
Add a call to get_ref
in resolve_refs_in_operation like
if "requestBody" in operation:
operation["requestBody"] = self.get_ref("request_body", operation["requestBody"])
self._resolve_refs_in_request_body(operation["requestBody"])
I haven't been looking to this code for a while so I may be mistaken again but I think the solution should be along these lines.
Can't look into it right now but anyone, feel free to work on this.
This is great, Jérôme :)
Thank you very much for this detailed guidance. I will try it and will let you know with results.
Thanks again and hopefully, we will get the easy solution like:
requestBody = "MyItem"
in the future updates :)
I sorry, but I can do these additions in my code by somehow inject / extend the ApiSpec functionality, or these updates need to be added to the ApiSpec core functionality in the future?
Yes, the feature should be added to apispec as per the "what's to be done" section of my comment.
You may try to achieve this in a local branch and propose a PR. (Feel free to ask if you're not used to do that.)
Thanks.
Thank you very much.
I will see if I have the time and might try to do something on it. For this I will check the ApiSpec contributing guidelines.
Hello there.
I am trying to create a path operation using ApiSpec as follows: apiSpec.path( path = "/my-item", operations = dict( post = dict( tags = ["MyItem"], operationId = "createMyItem", description = "Create MyItem", requestBody ={ "$ref": "#/components/requestBodies/MyItem" } , responses = {'200': {'$ref': '#/components/responses/OK'}, '500': {'$ref': '#/components/responses/GeneralError'}} ) ))
When I try to pass the ResponseBody as ref, as above, I get below error:
**File "c:\workspace.venv\Lib\site-packages\apispec\core.py", line 549, in path self.components.resolve_refs_in_path(self._paths[path]) File "c:\workspace.venv\Lib\site-packages\apispec\core.py", line 410, in resolve_refs_in_path self._resolve_refs_in_operation(path[method]) File "c:\workspace.venv\Lib\site-packages\apispec\core.py", line 382, in _resolve_refs_in_operation self._resolve_refs_in_request_body(operation["requestBody"]) File "c:\workspace.venv\Lib\site-packages\apispec\core.py", line 352, in _resolve_refs_in_request_body for media_type in request_body["content"].values():