Feature request: Support custom status codes of fine-grained responses for OpenAPI spec generation
Use case
For our APIs we sometimes have custom status codes in our success responses (for instance 201 Created) leading us to use the Response class.
The following (simplified) code:
@app.post("/subscriptions")
def create_subscription(
body: CreateSubscriptionRequest,
) -> Response[CreateSubscriptionResponse]:
"""Create a subscription."""
subscription_response = CreateSubscriptionResponse(**params)
return Response(
status_code=201,
body=subscription_response,
content_type=content_types.APPLICATION_JSON,
)
Results in this spec:
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateSubscriptionResponse"
}
}
}
}
However I was expecting this to work seamlessly with the openapi spec generation, but if we look at Route._get_openapi_path:
Working example:
@app.post(
"/subscriptions",
responses={201: {"description": "Successful Creation", "content": {"application/json": {"model": CreateSubscriptionResponse}}}},
)
def create_subscription(
body: CreateSubscriptionRequest,
) -> Response[CreateSubscriptionResponse]:
"""Create a subscription."""
subscription_response = CreateSubscriptionResponse(**params)
return Response(
status_code=201,
body=subscription_response,
content_type=content_types.APPLICATION_JSON,
)
I think it would be nice to not have to set the openapi responses in the decorater manually. However I see this might be hard as now its simply checking a type hint and the other would be an instance of Response.
Solution/User Experience
@app.post("/subscriptions")
def create_subscription(
body: CreateSubscriptionRequest,
) -> Response[CreateSubscriptionResponse]:
"""Create a subscription."""
subscription_response = CreateSubscriptionResponse(**params)
return Response(
status_code=201,
body=subscription_response,
content_type=content_types.APPLICATION_JSON,
)
I would like this to generate openapi spec with 201 response code.
Alternative solutions
Acknowledgment
- [x] This feature request meets Powertools for AWS Lambda (Python) Tenets
- [x] Should this be considered in other Powertools for AWS Lambda languages? i.e. Java, TypeScript, and .NET
Hi @RynoM – Thanks for submitting, I'll ensure this is brought up in our weekly planning session on Monday.
Hey @RynoM, thanks a lot for opening this feature request. I completely understand your point — sometimes I’d also like to have a way to infer responses directly from my code. However, in this specific case, I think we can’t do that. The Response object is designed to define fine-grained responses with additional headers, formats, and specific HTTP response statuses, so it’s fair to say that you can define any valid HTTP status code. To achieve what you’re describing, we would need to infer not only the type annotations — as the current implementation does — but also your actual code logic, which could go wrong in many ways.
1/ OpenAPI schema generation happens without needing to run your code; everything is inferred from type annotations. So, to implement what you’re suggesting, we would likely need to execute or analyze your code because the Response object could be encapsulated within another class or object.
2/ To avoid executing your code directly, we might try parsing and analyzing its AST, but that could have a significant performance impact.
3/ Another challenge is handling dynamic runtime conditions — if responses depend on variables or branching logic, static inference becomes unreliable.
4/ In my opinion, adopting this approach would complicate the documentation process and reduce maintainability since response inference logic could easily diverge from actual runtime behavior.
I’m open to hearing your points of view and exploring possible alternatives other tan to inferring the code.
I really appreciate your effort to bring ideas to improve the developer experience, but I think if we don't find a better alternative for this, we will close this issue as "not planned" for now.
Thanks
Hi @leandrodamascena thanks for your very detailed response. Given this context I agree that it doesnt make sense. Perhaps taking a step back; this issue is only here for us because we are forced to return a Response object as there is no way to only change the status code of a success response. Maybe an option in the decorator like success_status_code ?
This would result in:
@app.post("/items", success_status_code=201)
def create_item() -> SuccessModel:
...
return SuccessModel(...)
Removing the need for Response[SuccessModel] and the need to return a custom Response. If the open api schema generator could also use this status code it would be even better! Then it would also save us the responses={201: {"content": {"application/json": {"model": SuccessModel}}}} with only a single arg.