Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

--8<-- "LICENSE.rst"
--8<-- "LICENSE"
62 changes: 62 additions & 0 deletions docs/Usage/Request.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,65 @@ Magic:
![](../assets/Snipaste_2022-09-04_10-10-03.png)

More available fields to see [Parameter Object Fixed Fields](https://spec.openapis.org/oas/v3.1.0#fixed-fields-9).


## RequestBody

Sometimes, you may need to customize the Content-Type in the request body.

!!! warning

`request_body` may conflict with the `body` and `form` keyword, so try not to use them together unless the
content type wants to be the same.

```python
from flask import request
from pydantic import BaseModel

from flask_openapi import OpenAPI, RequestBody
from flask_openapi.utils import get_model_schema

app = OpenAPI(__name__)


class BookModel(BaseModel):
name: str
age: int


request_body_json = RequestBody(
description="The json request body",
content={"application/custom+json": {"schema": get_model_schema(BookModel)}},
)


@app.post("/json", request_body=request_body_json)
def post_json(body: BookModel):
print(request.headers.get("content-type"))
print(body.model_json_schema())
return {"message": "Hello World"}


request_body = RequestBody(
description="The multi request body",
content={
"text/plain": {"schema": {"type": "string"}},
"text/html": {"schema": {"type": "string"}},
"image/png": {"schema": {"type": "string", "format": "binary"}},
},
)


@app.post("/text", request_body=request_body)
def post_csv():
print(request.headers.get("content-type"))
data = request.data
print(data)
return {"message": "Hello World"}


if __name__ == "__main__":
print(app.url_map)
app.run()

```
1 change: 0 additions & 1 deletion docs/Usage/Response.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class BookResponse(BaseModel):
tags=[book_tag],
responses={
200: BookResponse,
# Version 2.4.0 starts supporting response for dictionary types
201: {"content": {"text/csv": {"schema": {"type": "string"}}}}
})
def get_book(path: BookPath, query: BookBody):
Expand Down
48 changes: 48 additions & 0 deletions examples/request_body_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from flask import request
from pydantic import BaseModel

from flask_openapi import OpenAPI, RequestBody
from flask_openapi.utils import get_model_schema

app = OpenAPI(__name__)


class BookModel(BaseModel):
name: str
age: int


request_body_json = RequestBody(
description="The json request body",
content={"application/custom+json": {"schema": get_model_schema(BookModel)}},
)


@app.post("/json", request_body=request_body_json)
def post_json(body: BookModel):
print(request.headers.get("content-type"))
print(body.model_json_schema())
return {"message": "Hello World"}


request_body = RequestBody(
description="The multi request body",
content={
"text/plain": {"schema": {"type": "string"}},
"text/html": {"schema": {"type": "string"}},
"image/png": {"schema": {"type": "string", "format": "binary"}},
},
)


@app.post("/text", request_body=request_body)
def post_csv():
print(request.headers.get("content-type"))
data = request.data
print(data)
return {"message": "Hello World"}


if __name__ == "__main__":
print(app.url_map)
app.run()
41 changes: 32 additions & 9 deletions flask_openapi/blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from flask import Blueprint

from .endpoint import create_view_func
from .models import ExternalDocumentation, Server, Tag
from .models import ExternalDocumentation, RequestBody, Server, Tag
from .types import ParametersTuple, ResponseDict
from .utils import (
HTTPMethod,
Expand Down Expand Up @@ -110,11 +110,12 @@ def _collect_openapi_info(
description: str | None = None,
external_docs: ExternalDocumentation | dict[str, Any] | None = None,
operation_id: str | None = None,
responses: ResponseDict | None = None,
deprecated: bool | None = None,
security: list[dict[str, list[Any]]] | None = None,
servers: list[Server | dict[str, Any]] | None = None,
openapi_extensions: dict[str, Any] | None = None,
request_body: RequestBody | dict[str, Any] | None = None,
responses: ResponseDict | None = None,
doc_ui: bool = True,
method: str = HTTPMethod.GET,
) -> ParametersTuple:
Expand All @@ -129,11 +130,12 @@ def _collect_openapi_info(
description: A verbose explanation of the operation behavior.
external_docs: Additional external documentation for this operation.
operation_id: Unique string used to identify the operation.
responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
deprecated: Declares this operation to be deprecated.
security: A declaration of which security mechanisms can be used for this operation.
servers: An alternative server array to service this operation.
openapi_extensions: Allows extensions to the OpenAPI Schema.
request_body: Advanced configuration in OpenAPI.
responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
doc_ui: Declares this operation to be shown. Default to True.
"""
if self.doc_ui is True and doc_ui is True:
Expand Down Expand Up @@ -175,6 +177,10 @@ def _collect_openapi_info(
tags = (tags or []) + self.abp_tags
parse_and_store_tags(tags, self.tags, self.tag_names, operation)

# Parse request body
if isinstance(request_body, dict):
request_body = RequestBody(**request_body)

# Parse response
get_responses(combine_responses, self.components_schemas, operation)

Expand All @@ -185,7 +191,12 @@ def _collect_openapi_info(
parse_method(uri, method, self.paths, operation)

# Parse parameters
return parse_parameters(func, components_schemas=self.components_schemas, operation=operation)
return parse_parameters(
func,
components_schemas=self.components_schemas,
operation=operation,
request_body=request_body,
)
else:
return parse_parameters(func, doc_ui=False)

Expand Down Expand Up @@ -236,11 +247,11 @@ def decorator(func) -> Callable:
description=description,
external_docs=external_docs,
operation_id=operation_id,
responses=responses,
deprecated=deprecated,
security=security,
servers=servers,
openapi_extensions=openapi_extensions,
responses=responses,
doc_ui=doc_ui,
method=HTTPMethod.GET,
)
Expand Down Expand Up @@ -277,6 +288,7 @@ def post(
security: list[dict[str, list[Any]]] | None = None,
servers: list[Server | dict[str, Any]] | None = None,
openapi_extensions: dict[str, Any] | None = None,
request_body: RequestBody | dict[str, Any] | None = None,
responses: ResponseDict | None = None,
validate_response: bool | None = None,
doc_ui: bool = True,
Expand All @@ -297,6 +309,7 @@ def post(
security: A declaration of which security mechanisms can be used for this operation.
servers: An alternative server array to service this operation.
openapi_extensions: Allows extensions to the OpenAPI Schema.
request_body: Advanced configuration in OpenAPI.
responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
validate_response: Verify the response body.
doc_ui: Declares this operation to be shown. Default to True.
Expand All @@ -311,11 +324,12 @@ def decorator(func) -> Callable:
description=description,
external_docs=external_docs,
operation_id=operation_id,
responses=responses,
deprecated=deprecated,
security=security,
servers=servers,
openapi_extensions=openapi_extensions,
request_body=request_body,
responses=responses,
doc_ui=doc_ui,
method=HTTPMethod.POST,
)
Expand Down Expand Up @@ -352,6 +366,7 @@ def put(
security: list[dict[str, list[Any]]] | None = None,
servers: list[Server | dict[str, Any]] | None = None,
openapi_extensions: dict[str, Any] | None = None,
request_body: RequestBody | dict[str, Any] | None = None,
responses: ResponseDict | None = None,
validate_response: bool | None = None,
doc_ui: bool = True,
Expand All @@ -372,6 +387,7 @@ def put(
security: A declaration of which security mechanisms can be used for this operation.
servers: An alternative server array to service this operation.
openapi_extensions: Allows extensions to the OpenAPI Schema.
request_body: Advanced configuration in OpenAPI.
responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
validate_response: Verify the response body.
doc_ui: Declares this operation to be shown. Default to True.
Expand All @@ -386,11 +402,12 @@ def decorator(func) -> Callable:
description=description,
external_docs=external_docs,
operation_id=operation_id,
responses=responses,
deprecated=deprecated,
security=security,
servers=servers,
openapi_extensions=openapi_extensions,
request_body=request_body,
responses=responses,
doc_ui=doc_ui,
method=HTTPMethod.PUT,
)
Expand Down Expand Up @@ -427,6 +444,7 @@ def delete(
security: list[dict[str, list[Any]]] | None = None,
servers: list[Server | dict[str, Any]] | None = None,
openapi_extensions: dict[str, Any] | None = None,
request_body: RequestBody | dict[str, Any] | None = None,
responses: ResponseDict | None = None,
validate_response: bool | None = None,
doc_ui: bool = True,
Expand All @@ -447,6 +465,7 @@ def delete(
security: A declaration of which security mechanisms can be used for this operation.
servers: An alternative server array to service this operation.
openapi_extensions: Allows extensions to the OpenAPI Schema.
request_body: Advanced configuration in OpenAPI.
responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
validate_response: Verify the response body.
doc_ui: Declares this operation to be shown. Default to True.
Expand All @@ -461,11 +480,12 @@ def decorator(func) -> Callable:
description=description,
external_docs=external_docs,
operation_id=operation_id,
responses=responses,
deprecated=deprecated,
security=security,
servers=servers,
openapi_extensions=openapi_extensions,
request_body=request_body,
responses=responses,
doc_ui=doc_ui,
method=HTTPMethod.DELETE,
)
Expand Down Expand Up @@ -502,6 +522,7 @@ def patch(
security: list[dict[str, list[Any]]] | None = None,
servers: list[Server | dict[str, Any]] | None = None,
openapi_extensions: dict[str, Any] | None = None,
request_body: RequestBody | dict[str, Any] | None = None,
responses: ResponseDict | None = None,
validate_response: bool | None = None,
doc_ui: bool = True,
Expand All @@ -522,6 +543,7 @@ def patch(
security: A declaration of which security mechanisms can be used for this operation.
servers: An alternative server array to service this operation.
openapi_extensions: Allows extensions to the OpenAPI Schema.
request_body: Advanced configuration in OpenAPI.
responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
validate_response: Verify the response body.
doc_ui: Declares this operation to be shown. Default to True.
Expand All @@ -536,11 +558,12 @@ def decorator(func) -> Callable:
description=description,
external_docs=external_docs,
operation_id=operation_id,
responses=responses,
deprecated=deprecated,
security=security,
servers=servers,
openapi_extensions=openapi_extensions,
request_body=request_body,
responses=responses,
doc_ui=doc_ui,
method=HTTPMethod.PATCH,
)
Expand Down
Loading