1313from typing import TypeVar
1414
1515from aiohttp import web
16- from common_library .json_serialization import json_dumps
16+ from common_library .user_messages import user_message
17+ from models_library .rest_error import EnvelopedError
1718from pydantic import BaseModel , TypeAdapter , ValidationError
1819
1920from ..mimetype_constants import MIMETYPE_APPLICATION_JSON
2526
2627@contextmanager
2728def handle_validation_as_http_error (
28- * , error_msg_template : str , resource_name : str , use_error_v1 : bool
29+ * , error_msg_template : str , resource_name : str
2930) -> Iterator [None ]:
3031 """Context manager to handle ValidationError and reraise them as HTTPUnprocessableEntity error
3132
3233 Arguments:
3334 error_msg_template -- _description_
3435 resource_name --
35- use_error_v1 -- If True, it uses new error response
3636
3737 Raises:
3838 web.HTTPUnprocessableEntity: (422) raised from a ValidationError
@@ -43,49 +43,37 @@ def handle_validation_as_http_error(
4343 yield
4444
4545 except ValidationError as err :
46- details = [
46+ # SEE https://github.com/ITISFoundation/osparc-simcore/issues/443
47+ _details = [
4748 {
48- "loc" : "." .join (map (str , e ["loc" ])),
49+ "loc" : "." .join (map (str , e ["loc" ])), # e.g. "body.name"
4950 "msg" : e ["msg" ],
5051 "type" : e ["type" ],
5152 }
5253 for e in err .errors ()
5354 ]
54- user_error_message = error_msg_template .format (
55- failed = ", " .join (d ["loc" ] for d in details )
56- )
57-
58- if use_error_v1 :
59- # NOTE: keeps backwards compatibility until ligher error response is implemented in the entire API
60- # Implements servicelib.aiohttp.rest_responses.ErrorItemType
61- errors = [
62- {
63- "code" : e ["type" ],
64- "message" : e ["msg" ],
65- "resource" : resource_name ,
66- "field" : e ["loc" ],
67- }
68- for e in details
69- ]
70- error_json_str = json_dumps (
71- {
72- "error" : {
73- "status" : status .HTTP_422_UNPROCESSABLE_ENTITY ,
74- "errors" : errors ,
75- }
76- }
77- )
78- else :
79- # NEW proposed error for https://github.com/ITISFoundation/osparc-simcore/issues/443
80- error_json_str = json_dumps (
81- {
82- "error" : {
83- "msg" : user_error_message ,
84- "resource" : resource_name , # optional
85- "details" : details , # optional
86- }
55+
56+ errors_details = [
57+ {
58+ "code" : e ["type" ],
59+ "message" : e ["msg" ],
60+ "resource" : resource_name ,
61+ "field" : e ["loc" ],
62+ }
63+ for e in _details
64+ ]
65+
66+ error_json_str = EnvelopedError .model_validate (
67+ {
68+ "error" : {
69+ "message" : error_msg_template .format (
70+ failed = ", " .join (e ["field" ] for e in errors_details )
71+ ),
72+ "status" : status .HTTP_422_UNPROCESSABLE_ENTITY ,
73+ "errors" : errors_details ,
8774 }
88- )
75+ }
76+ ).model_dump_json (exclude_unset = True , exclude_none = True )
8977
9078 raise web .HTTPUnprocessableEntity ( # 422
9179 text = error_json_str ,
@@ -104,15 +92,10 @@ def handle_validation_as_http_error(
10492def parse_request_path_parameters_as (
10593 parameters_schema_cls : type [ModelClass ],
10694 request : web .Request ,
107- * ,
108- use_enveloped_error_v1 : bool = True ,
10995) -> ModelClass :
11096 """Parses path parameters from 'request' and validates against 'parameters_schema'
11197
11298
113- Keyword Arguments:
114- use_enveloped_error_v1 -- new enveloped error model (default: {True})
115-
11699 Raises:
117100 web.HTTPUnprocessableEntity: (422) if validation of parameters fail
118101
@@ -121,9 +104,10 @@ def parse_request_path_parameters_as(
121104 """
122105
123106 with handle_validation_as_http_error (
124- error_msg_template = "Invalid parameter/s '{failed}' in request path" ,
107+ error_msg_template = user_message (
108+ "Invalid parameter/s '{failed}' in request path"
109+ ),
125110 resource_name = request .rel_url .path ,
126- use_error_v1 = use_enveloped_error_v1 ,
127111 ):
128112 data = dict (request .match_info )
129113 return parameters_schema_cls .model_validate (data )
@@ -132,15 +116,10 @@ def parse_request_path_parameters_as(
132116def parse_request_query_parameters_as (
133117 parameters_schema_cls : type [ModelClass ],
134118 request : web .Request ,
135- * ,
136- use_enveloped_error_v1 : bool = True ,
137119) -> ModelClass :
138120 """Parses query parameters from 'request' and validates against 'parameters_schema'
139121
140122
141- Keyword Arguments:
142- use_enveloped_error_v1 -- new enveloped error model (default: {True})
143-
144123 Raises:
145124 web.HTTPUnprocessableEntity: (422) if validation of parameters fail
146125
@@ -149,9 +128,10 @@ def parse_request_query_parameters_as(
149128 """
150129
151130 with handle_validation_as_http_error (
152- error_msg_template = "Invalid parameter/s '{failed}' in request query" ,
131+ error_msg_template = user_message (
132+ "Invalid parameter/s '{failed}' in request query"
133+ ),
153134 resource_name = request .rel_url .path ,
154- use_error_v1 = use_enveloped_error_v1 ,
155135 ):
156136 # NOTE: Currently, this does not take into consideration cases where there are multiple
157137 # query parameters with the same key. However, we are not using such cases anywhere at the moment.
@@ -166,13 +146,12 @@ def parse_request_query_parameters_as(
166146def parse_request_headers_as (
167147 parameters_schema_cls : type [ModelClass ],
168148 request : web .Request ,
169- * ,
170- use_enveloped_error_v1 : bool = True ,
171149) -> ModelClass :
172150 with handle_validation_as_http_error (
173- error_msg_template = "Invalid parameter/s '{failed}' in request headers" ,
151+ error_msg_template = user_message (
152+ "Invalid parameter/s '{failed}' in request headers"
153+ ),
174154 resource_name = request .rel_url .path ,
175- use_error_v1 = use_enveloped_error_v1 ,
176155 ):
177156 data = dict (request .headers )
178157 return parameters_schema_cls .model_validate (data )
@@ -181,8 +160,6 @@ def parse_request_headers_as(
181160async def parse_request_body_as (
182161 model_schema_cls : type [ModelOrListOrDictType ],
183162 request : web .Request ,
184- * ,
185- use_enveloped_error_v1 : bool = True ,
186163) -> ModelOrListOrDictType :
187164 """Parses and validates request body against schema
188165
@@ -197,9 +174,8 @@ async def parse_request_body_as(
197174 Validated model of request body
198175 """
199176 with handle_validation_as_http_error (
200- error_msg_template = "Invalid field/s '{failed}' in request body" ,
177+ error_msg_template = user_message ( "Invalid field/s '{failed}' in request body" ) ,
201178 resource_name = request .rel_url .path ,
202- use_error_v1 = use_enveloped_error_v1 ,
203179 ):
204180 if not request .can_read_body :
205181 # requests w/o body e.g. when model-schema is fully optional
0 commit comments