From 599a2ca4774735468dd59fea93d41b9e936f4833 Mon Sep 17 00:00:00 2001 From: Nikita Vakula <52108696+krjakbrjak@users.noreply.github.com> Date: Mon, 7 Jun 2021 06:00:04 +0200 Subject: [PATCH] Add validators to models fields (#9668) * [python-fastapi] Apply constraints to models Signed-off-by: Nikita Vakula * [python-fastapi] Use pydantic types to validate models fields Some data formats can be validated by annotating fields with some special pydantic data types (EmailStr, forr example). Signed-off-by: Nikita Vakula * [python-fastapi] Updated samples Signed-off-by: Nikita Vakula --- .../resources/python-fastapi/model.mustache | 42 ++++++++++++++++++- .../python-fastapi/model_field_type.mustache | 1 + .../src/openapi_server/models/api_response.py | 3 +- .../src/openapi_server/models/category.py | 8 +++- .../src/openapi_server/models/order.py | 3 +- .../src/openapi_server/models/pet.py | 3 +- .../src/openapi_server/models/tag.py | 3 +- .../src/openapi_server/models/user.py | 3 +- 8 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/python-fastapi/model_field_type.mustache diff --git a/modules/openapi-generator/src/main/resources/python-fastapi/model.mustache b/modules/openapi-generator/src/main/resources/python-fastapi/model.mustache index e56ef26d51..4c5545e079 100644 --- a/modules/openapi-generator/src/main/resources/python-fastapi/model.mustache +++ b/modules/openapi-generator/src/main/resources/python-fastapi/model.mustache @@ -2,9 +2,10 @@ from datetime import date, datetime # noqa: F401 +import re # noqa: F401 from typing import Dict, List, Optional # noqa: F401 -from pydantic import BaseModel, EmailStr, validator # noqa: F401 +from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 {{#models}} {{#model}} {{#pyImports}} @@ -29,7 +30,44 @@ class {{classname}}(BaseModel): """ {{#vars}} - {{name}}: {{#required}}{{dataType}}{{/required}}{{^required}}Optional[{{dataType}}] = None{{/required}} + {{name}}: {{#required}}{{>model_field_type}}{{/required}}{{^required}}Optional[{{>model_field_type}}] = None{{/required}} +{{/vars}} +{{#vars}} +{{#maximum}} + + @validator("{{name}}") + def {{name}}_max(cls, value): + assert value <= {{maximum}} + return value +{{/maximum}} +{{#minimum}} + + @validator("{{name}}") + def {{name}}_min(cls, value): + assert value >= {{minimum}} + return value +{{/minimum}} +{{#minLength}} + + @validator("{{name}}") + def {{name}}_min_length(cls, value): + assert len(value) >= {{minLength}} + return value +{{/minLength}} +{{#maxLength}} + + @validator("{{name}}") + def {{name}}_max_length(cls, value): + assert len(value) <= {{maxLength}} + return value +{{/maxLength}} +{{#pattern}} + + @validator("{{name}}") + def {{name}}_pattern(cls, value): + assert value is not None and re.match(r"{{pattern}}", value) + return value +{{/pattern}} {{/vars}} {{/model}} {{/models}} diff --git a/modules/openapi-generator/src/main/resources/python-fastapi/model_field_type.mustache b/modules/openapi-generator/src/main/resources/python-fastapi/model_field_type.mustache new file mode 100644 index 0000000000..c7e36fc47f --- /dev/null +++ b/modules/openapi-generator/src/main/resources/python-fastapi/model_field_type.mustache @@ -0,0 +1 @@ +{{#isEmail}}EmailStr{{/isEmail}}{{#isUri}}AnyUrl{{/isUri}}{{^isEmail}}{{^isUri}}{{dataType}}{{/isUri}}{{/isEmail}} \ No newline at end of file diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/models/api_response.py b/samples/server/petstore/python-fastapi/src/openapi_server/models/api_response.py index 8819c50aee..d5d1d9280c 100644 --- a/samples/server/petstore/python-fastapi/src/openapi_server/models/api_response.py +++ b/samples/server/petstore/python-fastapi/src/openapi_server/models/api_response.py @@ -2,9 +2,10 @@ from datetime import date, datetime # noqa: F401 +import re # noqa: F401 from typing import Dict, List, Optional # noqa: F401 -from pydantic import BaseModel, EmailStr, validator # noqa: F401 +from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 class ApiResponse(BaseModel): diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/models/category.py b/samples/server/petstore/python-fastapi/src/openapi_server/models/category.py index 0a16035992..c690b247ac 100644 --- a/samples/server/petstore/python-fastapi/src/openapi_server/models/category.py +++ b/samples/server/petstore/python-fastapi/src/openapi_server/models/category.py @@ -2,9 +2,10 @@ from datetime import date, datetime # noqa: F401 +import re # noqa: F401 from typing import Dict, List, Optional # noqa: F401 -from pydantic import BaseModel, EmailStr, validator # noqa: F401 +from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 class Category(BaseModel): @@ -20,3 +21,8 @@ class Category(BaseModel): id: Optional[int] = None name: Optional[str] = None + + @validator("name") + def name_pattern(cls, value): + assert value is not None and re.match(r"^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$", value) + return value diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/models/order.py b/samples/server/petstore/python-fastapi/src/openapi_server/models/order.py index 64e50546a3..8cf86bb6a5 100644 --- a/samples/server/petstore/python-fastapi/src/openapi_server/models/order.py +++ b/samples/server/petstore/python-fastapi/src/openapi_server/models/order.py @@ -2,9 +2,10 @@ from datetime import date, datetime # noqa: F401 +import re # noqa: F401 from typing import Dict, List, Optional # noqa: F401 -from pydantic import BaseModel, EmailStr, validator # noqa: F401 +from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 class Order(BaseModel): diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/models/pet.py b/samples/server/petstore/python-fastapi/src/openapi_server/models/pet.py index bfaf8a909e..9a688f83b1 100644 --- a/samples/server/petstore/python-fastapi/src/openapi_server/models/pet.py +++ b/samples/server/petstore/python-fastapi/src/openapi_server/models/pet.py @@ -2,9 +2,10 @@ from datetime import date, datetime # noqa: F401 +import re # noqa: F401 from typing import Dict, List, Optional # noqa: F401 -from pydantic import BaseModel, EmailStr, validator # noqa: F401 +from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 from openapi_server.models.category import Category from openapi_server.models.tag import Tag diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/models/tag.py b/samples/server/petstore/python-fastapi/src/openapi_server/models/tag.py index 96d92a6ab9..47ad31d81d 100644 --- a/samples/server/petstore/python-fastapi/src/openapi_server/models/tag.py +++ b/samples/server/petstore/python-fastapi/src/openapi_server/models/tag.py @@ -2,9 +2,10 @@ from datetime import date, datetime # noqa: F401 +import re # noqa: F401 from typing import Dict, List, Optional # noqa: F401 -from pydantic import BaseModel, EmailStr, validator # noqa: F401 +from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 class Tag(BaseModel): diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/models/user.py b/samples/server/petstore/python-fastapi/src/openapi_server/models/user.py index 20bea97e57..e6abfd9a5d 100644 --- a/samples/server/petstore/python-fastapi/src/openapi_server/models/user.py +++ b/samples/server/petstore/python-fastapi/src/openapi_server/models/user.py @@ -2,9 +2,10 @@ from datetime import date, datetime # noqa: F401 +import re # noqa: F401 from typing import Dict, List, Optional # noqa: F401 -from pydantic import BaseModel, EmailStr, validator # noqa: F401 +from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 class User(BaseModel):