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

Defining the request body type in a dynamically created endpoint - typing issues #2901

Closed
9 tasks done
provinzkraut opened this issue Mar 5, 2021 · 5 comments
Closed
9 tasks done
Labels
question Question or problem question-migrate

Comments

@provinzkraut
Copy link

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 one of:
    • Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
    • 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

Here's a self-contained, minimal, reproducible, example with my use case:

from typing import Type
from pydantic import BaseModel
from fastapi import FastAPI

app = FastAPI()


def create_endpoint(model: Type[BaseModel]):
    @app.post("/")
    def post(data: model):
        pass

Description

  • Run mypy against this snippet
  • Receive the error Variable "model" is not valid as a type

The provided example works as intended, but mypy - rightfully - complains about this since type variables cannot be used as types. The problem however is that using Type[...] to annotate create_endpoint is correct but there's no way (that I am aware of) in FastAPI to define the type of the request body other than with an annotation.

It would be really great to have a different way to achieve this, because as of now, dynamically creating endpoints like this is a bit inconvenient.

Environment

  • OS: Debian 10.8
  • FastAPI Version: 0.63.0
  • Python version: 3.8.6
@provinzkraut provinzkraut added the question Question or problem label Mar 5, 2021
@Kludex
Copy link
Member

Kludex commented Mar 5, 2021

There's a difference between runtime and when the type checking happens.

References:

Maybe using Generic class can help you?

@provinzkraut
Copy link
Author

provinzkraut commented Mar 5, 2021

@Kludex
Thank you for your suggestions!

I am aware of the differences between runtime typed and type checking, I'd just like to get them to play along nicely. Because as of now, I can either satisfy the type checker (i.e. using generics) or define the endpoint in a way FastAPI understands.

Could you elaborate how you think using generics could solve this problem?

Because so far, every approach I've tried leads to FastAPI not receiving the correct type for the body parameter.

@Kludex
Copy link
Member

Kludex commented Mar 5, 2021

I got some issues with the generics approach... And then I recalled that I've done something "similar".

Would you be satisfied with this https://github.com/Kludex/fastapi-health/blob/main/fastapi_health/route.py ?

You'd need to change the implementation, but what I wanted to show you is the idea of it.

EDIT: I'm going to copy paste here because I don't know if I'll change that package later on:

from inspect import Parameter, Signature
from typing import Callable, List

from fastapi import Depends, Response


def health(conditions: List[Callable]):
    def endpoint(**dependencies):
        if all([dependency for dependency in dependencies.values()]):
            return Response(status_code=200)
        return Response(status_code=503)

    params = []
    for condition in conditions:
        params.append(
            Parameter(
                f"param_{condition.__name__}",
                kind=Parameter.POSITIONAL_OR_KEYWORD,
                annotation=bool,
                default=Depends(condition),
            )
        )
    endpoint.__signature__ = Signature(params)
    return endpoint

@provinzkraut
Copy link
Author

That's a very nice solution and indeed an approach that I can use. I'd just hoped that I wouldn't have to resort to such measures to achieve such a simple task.

It'd be great if FastAPI could provide a solution for this. Otherwise, maybe this could be included in the docs somewhere because I do think this is a relatively common thing to do.

@amacfie
Copy link
Contributor

amacfie commented May 26, 2022

I don't know if this should be closed since the given solution doesn't have checkable type annotations. You might as well stick with the original code and tell mypy to ignore the line.

See also microsoft/pyright#3510

@tiangolo tiangolo reopened this Feb 27, 2023
@fastapi fastapi locked and limited conversation to collaborators Feb 27, 2023
@tiangolo tiangolo converted this issue into discussion #6893 Feb 27, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
question Question or problem question-migrate
Projects
None yet
Development

No branches or pull requests

4 participants