Skip to content

Commit b6b3531

Browse files
committed
Catalog entrypoints response model excludes None fields
1 parent 26c54b5 commit b6b3531

File tree

3 files changed

+33
-15
lines changed

3 files changed

+33
-15
lines changed

services/catalog/src/simcore_service_catalog/api/routes/services.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,18 @@
2626

2727
ServicesSelection = Set[Tuple[str, str]]
2828

29+
# These are equivalent to pydantic export models but for responses
30+
# SEE https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict
31+
# SEE https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter
32+
RESPONSE_MODEL_POLICY = {
33+
"response_model_by_alias": True,
34+
"response_model_exclude_unset": False,
35+
"response_model_exclude_defaults": False,
36+
"response_model_exclude_none": True,
37+
}
2938

30-
@router.get("", response_model=List[ServiceOut])
39+
40+
@router.get("", response_model=List[ServiceOut], **RESPONSE_MODEL_POLICY)
3141
async def list_services(
3242
# pylint: disable=too-many-arguments
3343
user_id: PositiveInt,
@@ -150,7 +160,11 @@ async def list_services(
150160
return detailed_services
151161

152162

153-
@router.get("/{service_key:path}/{service_version}", response_model=ServiceOut)
163+
@router.get(
164+
"/{service_key:path}/{service_version}",
165+
response_model=ServiceOut,
166+
**RESPONSE_MODEL_POLICY,
167+
)
154168
async def get_service(
155169
# pylint: disable=too-many-arguments
156170
user_id: int,
@@ -220,7 +234,11 @@ async def get_service(
220234
return service
221235

222236

223-
@router.patch("/{service_key:path}/{service_version}", response_model=ServiceOut)
237+
@router.patch(
238+
"/{service_key:path}/{service_version}",
239+
response_model=ServiceOut,
240+
**RESPONSE_MODEL_POLICY,
241+
)
224242
async def modify_service(
225243
# pylint: disable=too-many-arguments
226244
user_id: int,

services/web/server/src/simcore_service_webserver/catalog_api_handlers.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@
3636

3737

3838
# SEE https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict
39-
EXPORT_POLICY = {
39+
RESPONSE_MODEL_POLICY = {
4040
"by_alias": True,
4141
"exclude_unset": False,
4242
"exclude_defaults": False,
43-
"exclude_none": False,
43+
"exclude_none": True,
4444
}
4545

4646
routes = RouteTableDef()
@@ -151,7 +151,7 @@ async def list_service_inputs_handler(request: Request):
151151

152152
# format response
153153
enveloped: str = json_dumps(
154-
{"data": [m.dict(**EXPORT_POLICY) for m in response_model]}
154+
{"data": [m.dict(**RESPONSE_MODEL_POLICY) for m in response_model]}
155155
)
156156
return web.Response(text=enveloped, content_type="application/json")
157157

@@ -172,7 +172,7 @@ async def get_service_input_handler(request: Request):
172172
)
173173

174174
# format response
175-
enveloped: str = json_dumps({"data": response_model.dict(**EXPORT_POLICY)})
175+
enveloped: str = json_dumps({"data": response_model.dict(**RESPONSE_MODEL_POLICY)})
176176
return web.Response(text=enveloped, content_type="application/json")
177177

178178

@@ -219,7 +219,7 @@ async def list_service_outputs_handler(request: Request):
219219

220220
# format response
221221
enveloped: str = json_dumps(
222-
{"data": [m.dict(**EXPORT_POLICY) for m in response_model]}
222+
{"data": [m.dict(**RESPONSE_MODEL_POLICY) for m in response_model]}
223223
)
224224
return web.Response(text=enveloped, content_type="application/json")
225225

@@ -242,7 +242,7 @@ async def get_service_output_handler(request: Request):
242242
)
243243

244244
# format response
245-
enveloped: str = json_dumps({"data": response_model.dict(**EXPORT_POLICY)})
245+
enveloped: str = json_dumps({"data": response_model.dict(**RESPONSE_MODEL_POLICY)})
246246
return web.Response(text=enveloped, content_type="application/json")
247247

248248

@@ -321,7 +321,7 @@ async def list_services(ctx: _RequestContext):
321321
ctx.app, ctx.user_id, ctx.product_name, only_key_versions=False
322322
)
323323
for service in services:
324-
replace_service_input_outputs(service, **EXPORT_POLICY)
324+
replace_service_input_outputs(service, **RESPONSE_MODEL_POLICY)
325325
return services
326326

327327

@@ -331,7 +331,7 @@ async def get_service(
331331
service = await catalog_client.get_service(
332332
ctx.app, ctx.user_id, service_key, service_version, ctx.product_name
333333
)
334-
replace_service_input_outputs(service, **EXPORT_POLICY)
334+
replace_service_input_outputs(service, **RESPONSE_MODEL_POLICY)
335335
return service
336336

337337

@@ -349,7 +349,7 @@ async def update_service(
349349
ctx.product_name,
350350
update_data,
351351
)
352-
replace_service_input_outputs(service, **EXPORT_POLICY)
352+
replace_service_input_outputs(service, **RESPONSE_MODEL_POLICY)
353353
return service
354354

355355

services/web/server/tests/unit/isolated/test_catalog_api_models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from pprint import pformat
88

99
import pytest
10-
from simcore_service_webserver.catalog_api_handlers import EXPORT_POLICY
10+
from simcore_service_webserver.catalog_api_handlers import RESPONSE_MODEL_POLICY
1111
from simcore_service_webserver.catalog_api_models import (
1212
ServiceInputApiOut,
1313
ServiceOutputApiOut,
@@ -29,7 +29,7 @@ def test_webserver_catalog_api_models(model_cls, model_cls_examples):
2929
assert model_instance, f"Failed with {name}"
3030

3131
# tests export policy w/o errors
32-
data = model_instance.dict(**EXPORT_POLICY)
32+
data = model_instance.dict(**RESPONSE_MODEL_POLICY)
3333
assert model_cls(**data) == model_instance
3434

3535

@@ -75,7 +75,7 @@ def test_from_catalog_to_webapi_service():
7575
}
7676

7777
webapi_service = deepcopy(catalog_service)
78-
replace_service_input_outputs(webapi_service, **EXPORT_POLICY)
78+
replace_service_input_outputs(webapi_service, **RESPONSE_MODEL_POLICY)
7979

8080
# TODO: dev checks... generalize
8181
assert webapi_service["outputs"]["outFile"]["unit"] is None

0 commit comments

Comments
 (0)