From 3ea7c1523de3ffb27f2dbcc609a741413f008127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Janek=20Nouvertn=C3=A9?= Date: Sat, 30 Mar 2024 19:30:31 +0100 Subject: [PATCH] fix(OpenAPI): Document unconsumed path parameters (#3295) * Document unconsumed path parameters --- .pre-commit-config.yaml | 1 + litestar/_openapi/parameters.py | 15 +- pyproject.toml | 1 + tests/unit/test_openapi/test_schema.py | 19 + .../test_converter.py | 909 +++++++++--------- 5 files changed, 505 insertions(+), 440 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ecf00f31c9..663cc85f86 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,6 +17,7 @@ repos: - id: end-of-file-fixer - id: mixed-line-ending - id: trailing-whitespace + exclude: "tests/unit/test_openapi/test_typescript_converter/test_converter.py" - repo: https://github.com/provinzkraut/unasyncd rev: "v0.7.1" hooks: diff --git a/litestar/_openapi/parameters.py b/litestar/_openapi/parameters.py index c3da5c431a..5dbe43f5ad 100644 --- a/litestar/_openapi/parameters.py +++ b/litestar/_openapi/parameters.py @@ -96,7 +96,7 @@ def __init__( self.parameters = ParameterCollection(route_handler) self.dependency_providers = route_handler.resolve_dependencies() self.layered_parameters = route_handler.resolve_layered_parameters() - self.path_parameters_names = {p.name for p in path_parameters} + self.path_parameters: dict[str, PathParameterDefinition] = {p.name: p for p in path_parameters} def create_parameter(self, field_definition: FieldDefinition, parameter_name: str) -> Parameter: """Create an OpenAPI Parameter instance for a field definition. @@ -111,7 +111,7 @@ def create_parameter(self, field_definition: FieldDefinition, parameter_name: st field_definition.kwarg_definition if isinstance(field_definition.kwarg_definition, ParameterKwarg) else None ) - if parameter_name in self.path_parameters_names: + if parameter_name in self.path_parameters: param_in = ParamType.PATH is_required = True result = self.schema_creator.for_field_definition(field_definition) @@ -215,6 +215,17 @@ def create_parameters_for_field_definitions(self, fields: dict[str, FieldDefinit def create_parameters_for_handler(self) -> list[Parameter]: """Create a list of path/query/header Parameter models for the given PathHandler.""" handler_fields = self.route_handler.parsed_fn_signature.parameters + # not all path parameters have to be consumed by the handler. Because even not + # consumed path parameters must still be specified, we create stub parameters + # for the unconsumed ones so a correct OpenAPI schema can be generated + params_not_consumed_by_handler = set(self.path_parameters) - handler_fields.keys() + handler_fields.update( + { + param_name: FieldDefinition.from_kwarg(self.path_parameters[param_name].type, name=param_name) + for param_name in params_not_consumed_by_handler + } + ) + self.create_parameters_for_field_definitions(handler_fields) return self.parameters.list() diff --git a/pyproject.toml b/pyproject.toml index 33d0b2bb3b..aa7f074a1b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -409,6 +409,7 @@ known-first-party = ["litestar", "tests", "examples"] "tests/unit/test_contrib/test_sqlalchemy/**/*.*" = ["UP006"] "tools/**/*.*" = ["D", "ARG", "EM", "TRY", "G", "FBT"] "tools/prepare_release.py" = ["S603", "S607"] +"tests/unit/test_openapi/test_typescript_converter/test_converter.py" = ["W293"] [tool.ruff.format] docstring-code-format = true diff --git a/tests/unit/test_openapi/test_schema.py b/tests/unit/test_openapi/test_schema.py index acae797c3c..5af6049fd9 100644 --- a/tests/unit/test_openapi/test_schema.py +++ b/tests/unit/test_openapi/test_schema.py @@ -35,6 +35,7 @@ from litestar.enums import ParamType from litestar.openapi.spec import ExternalDocumentation, OpenAPIType, Reference from litestar.openapi.spec.example import Example +from litestar.openapi.spec.parameter import Parameter as OpenAPIParameter from litestar.openapi.spec.schema import Schema from litestar.pagination import ClassicPagination, CursorPagination, OffsetPagination from litestar.params import KwargDefinition, Parameter, ParameterKwarg @@ -573,6 +574,7 @@ def test_default_not_provided_for_kwarg_but_for_field() -> None: def test_routes_with_different_path_param_types_get_merged() -> None: + # https://github.com/litestar-org/litestar/issues/2700 @get("/{param:int}") async def get_handler(param: int) -> None: pass @@ -586,3 +588,20 @@ async def post_handler(param: str) -> None: paths = app.openapi_schema.paths["/{param}"] assert paths.get is not None assert paths.post is not None + + +def test_unconsumed_path_parameters_are_documented() -> None: + # https://github.com/litestar-org/litestar/issues/3290 + @get("/{param:str}") + async def handler() -> None: + pass + + app = Litestar([handler]) + params = app.openapi_schema.paths["/{param}"].get.parameters # type: ignore[index, union-attr] + assert params + assert len(params) == 1 + param = params[0] + assert isinstance(param, OpenAPIParameter) + assert param.name == "param" + assert param.required is True + assert param.param_in is ParamType.PATH diff --git a/tests/unit/test_openapi/test_typescript_converter/test_converter.py b/tests/unit/test_openapi/test_typescript_converter/test_converter.py index 684ca8a5a7..0241f7152d 100644 --- a/tests/unit/test_openapi/test_typescript_converter/test_converter.py +++ b/tests/unit/test_openapi/test_typescript_converter/test_converter.py @@ -15,442 +15,475 @@ def test_openapi_to_typescript_converter(person_controller: Type[Controller], pe result = convert_openapi_to_typescript(openapi_schema=app.openapi_schema) assert ( - result.write().replace("\t", " ") == "export namespace API {\n" - "\texport namespace PetOwnerOrPetGetPetsOrOwners {\n" - "\texport namespace Http200 {\n" - "\texport type ResponseBody = ({\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies?: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "} | {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional?: null | string;\n" - "\tpets?: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies?: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "})[];\n" - "\n" - "\texport interface ResponseHeaders {\n" - '\t"x-my-tag"?: string;\n' - "};\n" - "};\n" - "\n" - "\texport namespace Http406 {\n" - "\texport type ResponseBody = {\n" - "\tdetail: string;\n" - "\textra?: Record | null | unknown[];\n" - "\tstatus_code: number;\n" - "};\n" - "};\n" - "};\n" - "\n" - "\texport namespace PetPets {\n" - "\texport namespace Http200 {\n" - "\texport type ResponseBody = {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies?: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "};\n" - "};\n" - "\n" - "\texport namespace ServiceIdPersonBulkBulkCreatePerson {\n" - "\texport interface HeaderParameters {\n" - "\tsecret: string;\n" - "};\n" - "\n" - "\texport namespace Http201 {\n" - "\texport type ResponseBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional: null | string;\n" - "\tpets: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "}[];\n" - "};\n" - "\n" - "\texport namespace Http400 {\n" - "\texport type ResponseBody = {\n" - "\tdetail: string;\n" - "\textra?: Record | null | unknown[];\n" - "\tstatus_code: number;\n" - "};\n" - "};\n" - "\n" - "\texport type RequestBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional: null | string;\n" - "\tpets: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "}[];\n" - "};\n" - "\n" - "\texport namespace ServiceIdPersonBulkBulkPartialUpdatePerson {\n" - "\texport interface HeaderParameters {\n" - "\tsecret: string;\n" - "};\n" - "\n" - "\texport namespace Http200 {\n" - "\texport type ResponseBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional: null | string;\n" - "\tpets: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "}[];\n" - "};\n" - "\n" - "\texport namespace Http400 {\n" - "\texport type ResponseBody = {\n" - "\tdetail: string;\n" - "\textra?: Record | null | unknown[];\n" - "\tstatus_code: number;\n" - "};\n" - "};\n" - "\n" - "\texport type RequestBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional: null | string;\n" - "\tpets: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "}[];\n" - "};\n" - "\n" - "\texport namespace ServiceIdPersonBulkBulkUpdatePerson {\n" - "\texport interface HeaderParameters {\n" - "\tsecret: string;\n" - "};\n" - "\n" - "\texport namespace Http200 {\n" - "\texport type ResponseBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional?: null | string;\n" - "\tpets?: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies?: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "}[];\n" - "};\n" - "\n" - "\texport namespace Http400 {\n" - "\texport type ResponseBody = {\n" - "\tdetail: string;\n" - "\textra?: Record | null | unknown[];\n" - "\tstatus_code: number;\n" - "};\n" - "};\n" - "\n" - "\texport type RequestBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional?: null | string;\n" - "\tpets?: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies?: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "}[];\n" - "};\n" - "\n" - "\texport namespace ServiceIdPersonCreatePerson {\n" - "\texport interface HeaderParameters {\n" - "\tsecret: string;\n" - "};\n" - "\n" - "\texport namespace Http201 {\n" - "\texport type ResponseBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional?: null | string;\n" - "\tpets?: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies?: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "};\n" - "};\n" - "\n" - "\texport namespace Http400 {\n" - "\texport type ResponseBody = {\n" - "\tdetail: string;\n" - "\textra?: Record | null | unknown[];\n" - "\tstatus_code: number;\n" - "};\n" - "};\n" - "\n" - "\texport type RequestBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional?: null | string;\n" - "\tpets?: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies?: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "};\n" - "};\n" - "\n" - "\texport namespace ServiceIdPersonDataclassGetPersonDataclass {\n" - "\texport namespace Http200 {\n" - "\texport type ResponseBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional?: null | string;\n" - "\tpets?: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies?: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "};\n" - "};\n" - "};\n" - "\n" - "\texport namespace ServiceIdPersonGetPersons {\n" - "\texport interface CookieParameters {\n" - "\tvalue: number;\n" - "};\n" - "\n" - "\texport interface HeaderParameters {\n" - "\tsecret: string;\n" - "};\n" - "\n" - "\texport namespace Http200 {\n" - "\texport type ResponseBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional?: null | string;\n" - "\tpets?: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies?: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "}[];\n" - "};\n" - "\n" - "\texport namespace Http400 {\n" - "\texport type ResponseBody = {\n" - "\tdetail: string;\n" - "\textra?: Record | null | unknown[];\n" - "\tstatus_code: number;\n" - "};\n" - "};\n" - "\n" - "\texport interface PathParameters {\n" - "\tservice_id: number;\n" - "};\n" - "\n" - "\texport interface QueryParameters {\n" - "\tfrom_date?: null | number | string | string;\n" - '\tgender?: "A" | "F" | "M" | "O" | ("A" | "F" | "M" | "O")[] | null;\n' - "\tname?: null | string | string[];\n" - "\tpage: number;\n" - "\tpageSize: number;\n" - "\tto_date?: null | number | string | string;\n" - "};\n" - "};\n" - "\n" - "\texport namespace ServiceIdPersonPersonIdDeletePerson {\n" - "\texport namespace Http204 {\n" - "\texport type ResponseBody = undefined;\n" - "};\n" - "\n" - "\texport namespace Http400 {\n" - "\texport type ResponseBody = {\n" - "\tdetail: string;\n" - "\textra?: Record | null | unknown[];\n" - "\tstatus_code: number;\n" - "};\n" - "};\n" - "\n" - "\texport interface PathParameters {\n" - "\tperson_id: string;\n" - "};\n" - "};\n" - "\n" - "\texport namespace ServiceIdPersonPersonIdGetPersonById {\n" - "\texport namespace Http200 {\n" - "\texport type ResponseBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional?: null | string;\n" - "\tpets?: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies?: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "};\n" - "};\n" - "\n" - "\texport namespace Http400 {\n" - "\texport type ResponseBody = {\n" - "\tdetail: string;\n" - "\textra?: Record | null | unknown[];\n" - "\tstatus_code: number;\n" - "};\n" - "};\n" - "\n" - "\texport interface PathParameters {\n" - "\tperson_id: string;\n" - "};\n" - "};\n" - "\n" - "\texport namespace ServiceIdPersonPersonIdPartialUpdatePerson {\n" - "\texport namespace Http200 {\n" - "\texport type ResponseBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional: null | string;\n" - "\tpets: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "};\n" - "};\n" - "\n" - "\texport namespace Http400 {\n" - "\texport type ResponseBody = {\n" - "\tdetail: string;\n" - "\textra?: Record | null | unknown[];\n" - "\tstatus_code: number;\n" - "};\n" - "};\n" - "\n" - "\texport interface PathParameters {\n" - "\tperson_id: string;\n" - "};\n" - "\n" - "\texport type RequestBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional: null | string;\n" - "\tpets: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "};\n" - "};\n" - "\n" - "\texport namespace ServiceIdPersonPersonIdUpdatePerson {\n" - "\texport namespace Http200 {\n" - "\texport type ResponseBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional?: null | string;\n" - "\tpets?: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies?: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "};\n" - "};\n" - "\n" - "\texport namespace Http400 {\n" - "\texport type ResponseBody = {\n" - "\tdetail: string;\n" - "\textra?: Record | null | unknown[];\n" - "\tstatus_code: number;\n" - "};\n" - "};\n" - "\n" - "\texport interface PathParameters {\n" - "\tperson_id: string;\n" - "};\n" - "\n" - "\texport type RequestBody = {\n" - "\tcomplex: {\n" - "\t\n" - "};\n" - "\tfirst_name: string;\n" - "\tid: string;\n" - "\tlast_name: string;\n" - "\toptional?: null | string;\n" - "\tpets?: null | {\n" - "\tage: number;\n" - "\tname: string;\n" - '\tspecies?: "Cat" | "Dog" | "Monkey" | "Pig";\n' - "}[];\n" - "};\n" - "};\n" - "};" + result.write() + == """export namespace API { + export namespace PetOwnerOrPetGetPetsOrOwners { + export namespace Http200 { + export type ResponseBody = ({ + age: number; + name: string; + species?: "Cat" | "Dog" | "Monkey" | "Pig"; +} | { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional?: null | string; + pets?: null | { + age: number; + name: string; + species?: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +})[]; + + export interface ResponseHeaders { + "x-my-tag"?: string; +}; +}; + + export namespace Http406 { + export type ResponseBody = { + detail: string; + extra?: Record | null | unknown[]; + status_code: number; +}; +}; +}; + + export namespace PetPets { + export namespace Http200 { + export type ResponseBody = { + age: number; + name: string; + species?: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}; +}; + + export namespace ServiceIdPersonBulkBulkCreatePerson { + export interface HeaderParameters { + secret: string; +}; + + export namespace Http201 { + export type ResponseBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional: null | string; + pets: null | { + age: number; + name: string; + species: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}[]; +}; + + export namespace Http400 { + export type ResponseBody = { + detail: string; + extra?: Record | null | unknown[]; + status_code: number; +}; +}; + + export interface PathParameters { + service_id: number; +}; + + export type RequestBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional: null | string; + pets: null | { + age: number; + name: string; + species: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}[]; +}; + + export namespace ServiceIdPersonBulkBulkPartialUpdatePerson { + export interface HeaderParameters { + secret: string; +}; + + export namespace Http200 { + export type ResponseBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional: null | string; + pets: null | { + age: number; + name: string; + species: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}[]; +}; + + export namespace Http400 { + export type ResponseBody = { + detail: string; + extra?: Record | null | unknown[]; + status_code: number; +}; +}; + + export interface PathParameters { + service_id: number; +}; + + export type RequestBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional: null | string; + pets: null | { + age: number; + name: string; + species: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}[]; +}; + + export namespace ServiceIdPersonBulkBulkUpdatePerson { + export interface HeaderParameters { + secret: string; +}; + + export namespace Http200 { + export type ResponseBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional?: null | string; + pets?: null | { + age: number; + name: string; + species?: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}[]; +}; + + export namespace Http400 { + export type ResponseBody = { + detail: string; + extra?: Record | null | unknown[]; + status_code: number; +}; +}; + + export interface PathParameters { + service_id: number; +}; + + export type RequestBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional?: null | string; + pets?: null | { + age: number; + name: string; + species?: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}[]; +}; + + export namespace ServiceIdPersonCreatePerson { + export interface HeaderParameters { + secret: string; +}; + + export namespace Http201 { + export type ResponseBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional?: null | string; + pets?: null | { + age: number; + name: string; + species?: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}; +}; + + export namespace Http400 { + export type ResponseBody = { + detail: string; + extra?: Record | null | unknown[]; + status_code: number; +}; +}; + + export interface PathParameters { + service_id: number; +}; + + export type RequestBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional?: null | string; + pets?: null | { + age: number; + name: string; + species?: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}; +}; + + export namespace ServiceIdPersonDataclassGetPersonDataclass { + export namespace Http200 { + export type ResponseBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional?: null | string; + pets?: null | { + age: number; + name: string; + species?: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}; +}; + + export namespace Http400 { + export type ResponseBody = { + detail: string; + extra?: Record | null | unknown[]; + status_code: number; +}; +}; + + export interface PathParameters { + service_id: number; +}; +}; + + export namespace ServiceIdPersonGetPersons { + export interface CookieParameters { + value: number; +}; + + export interface HeaderParameters { + secret: string; +}; + + export namespace Http200 { + export type ResponseBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional?: null | string; + pets?: null | { + age: number; + name: string; + species?: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}[]; +}; + + export namespace Http400 { + export type ResponseBody = { + detail: string; + extra?: Record | null | unknown[]; + status_code: number; +}; +}; + + export interface PathParameters { + service_id: number; +}; + + export interface QueryParameters { + from_date?: null | number | string | string; + gender?: "A" | "F" | "M" | "O" | ("A" | "F" | "M" | "O")[] | null; + name?: null | string | string[]; + page: number; + pageSize: number; + to_date?: null | number | string | string; +}; +}; + + export namespace ServiceIdPersonPersonIdDeletePerson { + export namespace Http204 { + export type ResponseBody = undefined; +}; + + export namespace Http400 { + export type ResponseBody = { + detail: string; + extra?: Record | null | unknown[]; + status_code: number; +}; +}; + + export interface PathParameters { + person_id: string; + service_id: number; +}; +}; + + export namespace ServiceIdPersonPersonIdGetPersonById { + export namespace Http200 { + export type ResponseBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional?: null | string; + pets?: null | { + age: number; + name: string; + species?: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}; +}; + + export namespace Http400 { + export type ResponseBody = { + detail: string; + extra?: Record | null | unknown[]; + status_code: number; +}; +}; + + export interface PathParameters { + person_id: string; + service_id: number; +}; +}; + + export namespace ServiceIdPersonPersonIdPartialUpdatePerson { + export namespace Http200 { + export type ResponseBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional: null | string; + pets: null | { + age: number; + name: string; + species: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}; +}; + + export namespace Http400 { + export type ResponseBody = { + detail: string; + extra?: Record | null | unknown[]; + status_code: number; +}; +}; + + export interface PathParameters { + person_id: string; + service_id: number; +}; + + export type RequestBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional: null | string; + pets: null | { + age: number; + name: string; + species: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}; +}; + + export namespace ServiceIdPersonPersonIdUpdatePerson { + export namespace Http200 { + export type ResponseBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional?: null | string; + pets?: null | { + age: number; + name: string; + species?: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}; +}; + + export namespace Http400 { + export type ResponseBody = { + detail: string; + extra?: Record | null | unknown[]; + status_code: number; +}; +}; + + export interface PathParameters { + person_id: string; + service_id: number; +}; + + export type RequestBody = { + complex: { + +}; + first_name: string; + id: string; + last_name: string; + optional?: null | string; + pets?: null | { + age: number; + name: string; + species?: "Cat" | "Dog" | "Monkey" | "Pig"; +}[]; +}; +}; +};""" )