From 281023acbcbed18031aadb3d8db76d7fe8a89ad8 Mon Sep 17 00:00:00 2001 From: Aadesh-Baral Date: Tue, 27 Jun 2023 11:34:23 +0545 Subject: [PATCH 1/3] Modify decorator to set preferred_locale in dto class using header accept-language. --- backend/models/dtos/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/models/dtos/__init__.py b/backend/models/dtos/__init__.py index 457fd2410a..3b4795feda 100644 --- a/backend/models/dtos/__init__.py +++ b/backend/models/dtos/__init__.py @@ -46,6 +46,12 @@ def wrapper(*args, **kwargs): if "user_id" in dto.__class__._fields: dto.user_id = token_auth.current_user() + # Get accepted languages from request header + if "preferred_locale" in dto.__class__._fields: + dto.preferred_locale = request.environ.get( + "HTTP_ACCEPT_LANGUAGE", "en" + ) + dto.validate() request.validated_dto = ( dto # Set validated DTO on request object for use in view function From 2a1ab0c2476ace1810ca7f3a805d2869d7396879 Mon Sep 17 00:00:00 2001 From: Aadesh-Baral Date: Tue, 27 Jun 2023 11:36:16 +0545 Subject: [PATCH 2/3] Fix serialized name handling in validate_request decorator --------------------------------------- The previous implementation of the validate_request decorator did not correctly handle the serialized names of fields in the DTO class when populating attribute values from the request. This commit addresses the issue by updating the decorator to access the serialized names directly from the serialized_name attribute of each field. The updated implementation iterates over the fields in the DTO class and checks for the presence of the serialized names in the request body. If a matching serialized name is found, the corresponding value is assigned to the DTO attribute. This ensures that fields with serialized names, specified using the serialized_name parameter in the field definitions, are properly set. --- backend/models/dtos/__init__.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/backend/models/dtos/__init__.py b/backend/models/dtos/__init__.py index 3b4795feda..5b52341dbf 100644 --- a/backend/models/dtos/__init__.py +++ b/backend/models/dtos/__init__.py @@ -33,20 +33,24 @@ def wrapper(*args, **kwargs): try: dto = dto_class() - # Set attribute values from request body, query parameters, and path parameters for attr in dto.__class__._fields: - if request.is_json and attr in request.json: - setattr(dto, attr, request.json[attr]) - elif attr in request.args: - setattr(dto, attr, request.args.get(attr)) - elif attr in kwargs: - setattr(dto, attr, kwargs[attr]) + # Get serialized name of attr if exists otherwise use attr name + field = dto.__class__._fields[attr] + attr_name = field.serialized_name if field.serialized_name else attr + + # Set attribute value from request body, query parameters, or path parameters + if request.is_json and attr_name in request.json: + setattr(dto, attr, request.json[attr_name]) + elif attr_name in request.args: + setattr(dto, attr, request.args.get(attr_name)) + elif attr_name in kwargs: + setattr(dto, attr, kwargs[attr_name]) # Set authenticated user id if user_id is a field in the DTO if "user_id" in dto.__class__._fields: dto.user_id = token_auth.current_user() - # Get accepted languages from request header + # Get accepted language from request header if "preferred_locale" in dto.__class__._fields: dto.preferred_locale = request.environ.get( "HTTP_ACCEPT_LANGUAGE", "en" From 21558f1d3c204b17ac01e0737fd06c4ade4638b7 Mon Sep 17 00:00:00 2001 From: Aadesh-Baral Date: Wed, 28 Jun 2023 11:00:17 +0545 Subject: [PATCH 3/3] Update decorator to handle invalid/empty json body. ----------------------------------------------- This commit refactors the request body handling in the validate_request decorator. Previously, the code attempted to access request.json directly, which could raise a "Failed to decode JSON object" error when the request body was empty or contained invalid JSON. To address this issue, the code has been updated to use a try-except block. It now checks request.is_json and handles two scenarios: - If request.is_json is True, indicating a JSON content type, it tries to access request.json to retrieve the JSON payload. If the request body contains invalid JSON, the WerkzeugBadRequest exception is caught, and the body is set to an empty dictionary. - If request.is_json is False or request.json raises an error for any reason, body is also set to an empty dictionary. --- backend/models/dtos/__init__.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/backend/models/dtos/__init__.py b/backend/models/dtos/__init__.py index 5b52341dbf..61376b35ad 100644 --- a/backend/models/dtos/__init__.py +++ b/backend/models/dtos/__init__.py @@ -1,7 +1,7 @@ from functools import wraps from flask import request from schematics.exceptions import DataError - +from werkzeug.exceptions import BadRequest as WerkzeugBadRequest from backend.exceptions import BadRequest @@ -32,6 +32,12 @@ def wrapper(*args, **kwargs): try: dto = dto_class() + try: + body = request.json if request.is_json else {} + except ( + WerkzeugBadRequest + ): # If request body does not contain valid JSON then BadRequest is raised by Flask + body = {} for attr in dto.__class__._fields: # Get serialized name of attr if exists otherwise use attr name @@ -39,8 +45,8 @@ def wrapper(*args, **kwargs): attr_name = field.serialized_name if field.serialized_name else attr # Set attribute value from request body, query parameters, or path parameters - if request.is_json and attr_name in request.json: - setattr(dto, attr, request.json[attr_name]) + if attr_name in body: + setattr(dto, attr, body[attr_name]) elif attr_name in request.args: setattr(dto, attr, request.args.get(attr_name)) elif attr_name in kwargs: