aws-powertools/powertools-lambda-python

Feature request: Custom response validation status code on routes

amin-farjadi opened this issue · 2 comments

Use case

I have an api gateway resolver with numerous routes and validation enabled. For route "/a" the default if the response cannot be validated against the route's function's annotation would be a 422 response. I want route "/b" however, to return a 500 if its response could not be validated and route "/c" to return a 403.

Solution/User Experience

from pydantic import BaseModel

from aws_lambda_powertools.event_handler import APIGatewayRestResolver


app = APIGatewayRestResolver(enable_validation=True)

class Model(BaseModel):
    name: str
    age: int

@app.get("/a")
def handler_route_a() -> Model:
    return {"age": 18}  # type: ignore

@app.get(
    "/b",
    custom_response_validation_http_code=500,
)
def handler_route_b() -> Model:
    return {"age": 18}  # type: ignore

@app.get(
    "/c",
    custom_response_validation_http_code=403,
)
def handler_route_c() -> Model:
    return {"age": 18}  # type: ignore

event_a = {
  "path": "/a",
  "httpMethod": "GET",
}

event_b = {
  "path": "/b",
  "httpMethod": "GET",
}

event_c = {
  "path": "/c",
  "httpMethod": "GET",
}

result_a = app(event_a, {})
result_b = app(event_b, {})
result_c = app(event_c, {})


assert result_a["statusCode"] == 422
assert result_b["statusCode"] == 500
assert result_c["statusCode"] == 403

Alternative solutions

Acknowledgment

Hey @amin-farjadi! Thanks a lot for opening this issue and sorry for late reply! Since now we have the global response validation http code, we can move on per route implementation. I have some considerations:

1/ What about response_validation_error_http_code instead of custom_response_validation_http_code?
2/ In my opinion if a customer set response validation code per route, it should take precedence on the global one, what do you think? for example:

from aws_lambda_powertools.event_handler import APIGatewayRestResolver

app = APIGatewayRestResolver(
    enable_validation=True,
    response_validation_error_http_code=HTTPStatus.INTERNAL_SERVER_ERROR, 
)

@app.get(
    "/c",
    response_validation_error_http_code=403, # will overwrite the global, returning 403
)
def handler_route_c() -> Model:
    return {"age": 18}  # type: ignore

@app.get(
    "/d" # will return the global one, which is 500
)
def handler_route_d() -> Model:
    return {"age": 18}  # type: ignore

Please let me know what you think.