Feature request: alias generator for Query, Path or Header
Closed this issue ยท 23 comments
Use case
In a BaseModel you can setup an alias_generator.
It would be release nice to have something configurable for e.g. Query
Solution/User Experience
Think about this:
@app.get("/")
def list_something(max_results: Annotated[int, Query(alias="maxResults")]) -> Response[str]:
...could become something like this:
class CamelCaseQuery(Query):
field_config = {"alias_generator": alias_generators.to_camel}
@app.get("/")
def list_something(max_results: Annotated[int, CamelCaseQuery()]) -> Response[str]:
...Alternative solutions
Acknowledgment
- This feature request meets Powertools for AWS Lambda (Python) Tenets
- Should this be considered in other Powertools for AWS Lambda languages? i.e. Java, TypeScript, and .NET
Hi @tonnico, thanks for opening this issue! I know about the alias generator in Pydantic, but I might not understand your point here. Can you explain a bit more?
Thanks
Our default for query parameters is camelCase. It would be nice to setup this without repeating any time with an alias.
Maybe this should be a feature for pydantic FieldInfo?
Our default for query parameters is camelCase. It would be nice to setup this without repeating any time with an alias. Maybe this should be a feature for pydantic FieldInfo?
Aaa, thanks for explaining the use case, I get it now. The problem here is that Query inherits from FieldInfo and not from BaseModel, so there's no model_config that allows auto-transformation to camelCase. Also, the Pydantic documentation says (search for "camel") that the correct way is to use alias (which is what you're doing). So, yes, I think we can open a feature request in Pydantic.
I tried searching and didn't find anything: https://github.com/pydantic/pydantic/issues?q=sort%3Aupdated-desc%20is%3Aissue%20state%3Aopen%20fieldInfo%20camel
What do you think?
I think it is not possible to add such information to the type on some way. Probably the best solution would be to add something similar to FastAPI. There you are able to use complete BaseModel's for queries, headers and body.
class Q(BaseModel):
model_config = {"alias_generator": to_camel}
my_value: str
@app.get("/")
def list(q: Annotated[Q, Query()]):
return q.my_valueYeah, that make sense for me, but in this case we need to support Pydantic models when using Query/Headers and we don't support that yet. Do you want to submit a PR to implement it? I'd love to have this support and tbh I'm think to implement this soon.
I would love to implement this. However, I don't think I could start any earlier than November.
I would love to implement this. However, I don't think I could start any earlier than November.
Hey, thats ok @tonnico! I'll try to work on this in the next week and ping you for a review.
Sounds good, looking forward to it!
I'm working on this PR to add this support: #7076
Thanks, I'm looking into it.
I'm testing with this minimal.
from typing import Annotated
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from pydantic import BaseModel, StringConstraints
from aws_lambda_powertools.event_handler.openapi.params import Query
app = APIGatewayRestResolver(enable_validation=True)
class QueryParams(BaseModel):
full_name: Annotated[str, StringConstraints(min_length=5)]
@app.get("/query-model")
def query_model(
params: Annotated[QueryParams, Query()],
):
return {"fullName": params.full_name}While a missing value looks good.
{"statusCode":422,"detail":[{"loc":["query","full_name"],"type":"missing"}]}A request with full_name=abc gives me this error
{"statusCode":422,"detail":[{"loc":["query","params"],"type":"value_error"}]}Hi @tonnico, thanks a lot for validating this... but this is the expected behavior, isn't it? You're using Pydantic's StringConstraints and saying the minimum length is 5, but you're passing a string of length 3 and getting a validation error.
Running this same code with a valid string:
Am I missing something?
Hmmm, maybe you expected a better error description, because this should be a constraint validation error due to the minimum string length, is that it?
Yes, at least I would expect something like {"loc":["query","full_name"]... and not {"loc":["query","params"]...
Yes, at least I would expect something like
{"loc":["query","full_name"]...and not{"loc":["query","params"]...
Ok, thanks for confirming. I need to work here: https://github.com/aws-powertools/powertools-lambda-python/pull/7076/files#diff-f2877be00a4e8e930e5ca73ba8d56caf0eba726919a6b7c5349681bda5ca442cR356
Let me see if I can improve the error extraction message in this case. Any insight/debugging are welcome.
Hey @tonnico I made some changes in the PR to improve the error message + header serialization/validation, which was failing with fields using _.
Can you pls try again and let me know what you think? Also, if you have any advanced use case I'd love to test it.
Commit: 7c49d72
Btw, I still need to clean this code and improve some areas that I'm not happy, but I just want to see if this is good enough to ship to production after this optimization.
Hey,
I made a little repo for simple testing with some more advanced models.
https://github.com/tonnico/powertools-minimal
Just clone this repo close to the powertools and try it out.
.
โโโ powertools-lambda-python
โโโ powertools-minimal
currently the alias is not working as expected.
Thanks for sharing @tonnico, this is really helpful! I know what is going, I need to make the validation method more generic. I'll work on that this week.
Hi @tonnico, I made some additional changes to the PR and I'm validating your example! Everything seems to be working, but I'm still testing other things.
I hope to solve all the issues by next week, and then I'll clean up the code and tests.
Very nice work. I'm looking forward to test this in my productive code. Currently I'm in vacation for 2 weeks.
One point I was missing in the test section is a multi value query. E.g. endpoint?attr=a&attr=b would become "attr": ["a", "b"]. While this work in current annotations without BaseModel support I will expect that this will still work. So I think a test would be very nice.
@leandrodamascena I've added an example in my repo. Hope this helps.
@leandrodamascena Is it ok for you, when I create a PR on top of yours? I have solved some errors on my computer.
@leandrodamascena Is it ok for you, when I create a PR on top of yours? I have solved some errors on my computer.
Heyy @tonnico sure thing! Create another one and then we can close mine!
Warning
This issue is now closed. Please be mindful that future comments are hard for our team to see.
If you need more assistance, please either reopen the issue, or open a new issue referencing this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.