Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple aliases for query parameters #1889

Closed
9 tasks done
tomgrin10 opened this issue Aug 13, 2020 · 24 comments
Closed
9 tasks done

Multiple aliases for query parameters #1889

tomgrin10 opened this issue Aug 13, 2020 · 24 comments

Comments

@tomgrin10
Copy link

tomgrin10 commented Aug 13, 2020

First check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google "How to X in FastAPI" and didn't find any information.
  • I already read and followed all the tutorial in the docs and didn't find an answer.
  • I already checked if it is not related to FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.
  • After submitting this, I commit to:
    • Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
    • Or, I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
    • Implement a Pull Request for a confirmed bug.

Example

I would like to be able to do this:

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/")
def get(query: Optional[str] = Query(None, alias=['q', 'query']):
    return query

Description

Currently to give a query parameter multiple aliases, you need to declare multiple query parameters.

The solution you would like

Being able to give a list of aliases to the alias arg of the Query class.

Query(alias=['q', 'query'])

Of course backwards compatibility won'y break, as alias arg would be of type Optional[Union[str, Iterable[str]]].
You would still be able to do this:

Query(alias='q')

Describe alternatives you've considered

@Kludex mentioned creating a new argument aliases

Query(aliases=['q', 'query'])
@tomgrin10 tomgrin10 added the feature New feature or request label Aug 13, 2020
@Kludex
Copy link
Member

Kludex commented Aug 13, 2020

It probably should accept a str as well or maybe an alternative solution could be a field aliases.

@tomgrin10
Copy link
Author

It probably should accept a str as well or maybe an alternative solution could be a field aliases.

Yes, my intention was not to break compatibility and make it accept both an str and a Iterable[str], I'll edit my issue to make it more clear

@SirTelemak
Copy link

alias goes from pydantic so we can't make in on FastAPI layer (there is__slots__ defined for base class) as I can se it for now

@tomgrin10
Copy link
Author

alias goes from pydantic so we can't make in on FastAPI layer (there is__slots__ defined for base class) as I can se it for now

That sucks.
Maybe duplicate the query parameter object for each alias?

@SirTelemak
Copy link

At first I think you should look/open similar issue for Pydantic. Maybe there some workarounds or it's planned feature. Multiple params forone object seems wrong

@tomgrin10
Copy link
Author

At first I think you should look/open similar issue for Pydantic. Maybe there some workarounds or it's planned feature. Multiple params forone object seems wrong

Yea, I agree it's kinda hackish.
But if pydantic doesn't plan on supporting it, maybe it's the way to go.

@Kludex
Copy link
Member

Kludex commented Aug 13, 2020

Maybe useful: pydantic/pydantic#324 (2 years old)

@tomgrin10
Copy link
Author

So it doesn't seem like a pydantic solution is gonna happen any time soon, is there any progress on this?

@pmav99
Copy link

pmav99 commented Oct 8, 2020

is there any progress on this?

Opening a ticket with your proposal on the pydantic bug-tracker would probably help. Making a pull request even more so, but asking for some initial feedback on the API would probably be a good idea.

@NoahCardoza
Copy link

I think I found a possible solution without modifying pydantic. Not sure if it will be officially merged in but I'll try to submit a PR in the coming days.

Hopefully it helps a few people!

@ycd
Copy link
Contributor

ycd commented Oct 22, 2020

@NoahCardoza can you provide an example?

@NoahCardoza
Copy link

Still working out the kinks, but it looks like it's possible since pydantic collects any extra kwargs inside an extra property. I don't have the project open but I'll try to explain that changes and add some screenshots/examples after I get out of my first wave of meetings today 💀

@NoahCardoza
Copy link

Alright, so after more digging my original statement was incorrect. I was using the Query class:

@app.get("/")
def get(query: str = Query(None, aliases=['query', 'q'])):
    return query

However, pydantic's ModelField does not have a catch all. One solution to this would be something along the lines of:

class MultiAliasablModelField(ModelField):
    def __init__(self, *args, aliases: Optional[List[str]] = None, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.aliases = aliases

    def __repr_args__(self) -> str:
        args = super().__repr_args__()
        if self.aliases:
            args.append(('aliases', self.aliases))
        return args

This would require changes to the return annotations for the *_field functions, as well as other minor changes to handle the aliases property.

The get_param_field would then be able to pass the aliases via field_info.extra.get('aliases').

I've to to run at the moment, but I'll fork/branch and try to get a complete example ready ASAP.

@NoahCardoza
Copy link

Here is a working fix NoahCardoza/fastapi:feature/multiple-aliases! I need to do a little clean up and update the docs etc.

You'll also noticed a TODO which is looking more like a FIX now that I think about it... It's 4 AM.

Anyways, I'm not sure how a field with multiple aliases should properly render an error when it's a required field.

For reference, I'm using this code to test:

from typing import Optional
from pydantic import Required
from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/")
def get(
        question: str = Query(Required, aliases=('q', 'question')),
        answer: Optional[int] = Query(None, aliases=('a', 'answer'))
    ):
    return {
        'question': question,
        'answer': answer,
    }


app.setup()

And I'm using this script to test:

req() {
  curl -w "\n" "http://127.0.0.1:8000$1"
}

req
req "/?q=What%27s%20the%20answer%20to%20the%20universe?"
req "/?question=What%27s%20the%20answer%20to%20the%20universe?"
req "/?q=What%27s%20the%20answer%20to%20the%20universe?&a=42"
req "/?question=What%27s%20the%20answer%20to%20the%20universe?&answer=42"

Which you can diff against:

{"detail":[{"loc":["query",["q","question"]],"msg":"field required","type":"value_error.missing"}]}
{"question":"What's the answer to the universe?","answer":null}
{"question":"What's the answer to the universe?","answer":null}
{"question":"What's the answer to the universe?","answer":42}
{"question":"What's the answer to the universe?","answer":42}

@zhqu1148980644
Copy link

How's this going on?

1 similar comment
@vbigbang
Copy link

How's this going on?

@NoahCardoza
Copy link

Sorry @vbigbang and @zhqu1148980644, I've become busy with other things at the moment. If I can get back to this I will, but if anyone else wants to take it up from where I left off, feel free!

@iamthen0ise
Copy link

Sorry, but how this feature would appear in Swagger/OpenAPI generated by FastAPI?

@NoahCardoza
Copy link

@iamthen0ise If I remember correctly, I think that was one of the issues I was stuck on before I ran out of time... I'm not exactly sure.

@tiangolo
Copy link
Member

This will be possible with Pydantic v2, and once FastAPI is updated for Pydantic v2. 🚀

Because of that, it would actually be more of a Pydantic issue than a FastAPI issue. 🤓

Sorry for the long delay! 🙈 I wanted to personally address each issue and they piled up through time, but now I'm checking each one in order.

@github-actions
Copy link
Contributor

Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs.

@bkis
Copy link

bkis commented Nov 7, 2022

This will be possible with Pydantic v2, and once FastAPI is updated for Pydantic v2.
Because of that, it would actually be more of a Pydantic issue than a FastAPI issue.

But this question by @iamthen0ise is still a FastAPI issue, isn't it? How would this be handled?

@tiangolo
Copy link
Member

tiangolo commented Nov 7, 2022

Not sure yet how it would be handled. I haven't worked on that yet.

@bkis
Copy link

bkis commented Nov 8, 2022

I am not sure if this is helpful, but I'd like to share my perspective on this matter. As far as I see there are two kinds of related needs in functionality that come with very different impact on the existing implementation:

  1. The less intrusive way: The ability to define one "public" and one "internal" version/alias for parameter names to have e.g. camel-cased parameters (someParam) published via the API, while working with snake-cased (some_param) parameters internally. There'd be no ambiguity about what to display in the swagger doc, because there'd be only one "public" version of each parameter.
  2. Allowing arbitrary public parameter aliases. I can see that this might be handy in some situations, but it comes with some difficulties (like the above-mentioned swagger question) and might also unnecessarily bloat the framework. But maybe I just overlook an important use case for this.

I'd argue it's kind of a bummer no. 1 isn't possible.
Anyway, thank you a lot for this beautiful framework! I really enjoy working with it so far!

@tiangolo tiangolo removed the feature New feature or request label Feb 22, 2023
@tiangolo tiangolo added question Question or problem reviewed labels Feb 22, 2023
@tiangolo tiangolo reopened this Feb 28, 2023
@fastapi fastapi locked and limited conversation to collaborators Feb 28, 2023
@tiangolo tiangolo converted this issue into discussion #7233 Feb 28, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Projects
None yet
Development

No branches or pull requests