Code Monkey home page Code Monkey logo

fastapi's People

Contributors

alejsdev avatar alertred avatar alexandrhub avatar barsi avatar batlopes avatar dependabot[bot] avatar dmontagu avatar euri10 avatar github-actions[bot] avatar hard-coders avatar hasansezertasan avatar jaystone776 avatar kanikim avatar kludex avatar mariacamilagl avatar nilslindemann avatar ninahwang avatar pablocm83 avatar pre-commit-ci[bot] avatar rjnemo avatar runningikkyu avatar samuelcolvin avatar serrones avatar smlep avatar swftalpc avatar tiangolo avatar tokusumi avatar waynerv avatar xewus avatar xzmeng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fastapi's Issues

Return lists

Hi there!

First of all, gerat project! Thank You for sharing it!

i'm a somewhat a beginner, i'd like some help if you guys don't mind. (I couldn't find another forum for questions)

I've managed to read a list of objects inside a json, by passing the body like this:

[
  {
    "name": "Item name example 1",
    "price": 100,
    "is_offer": true
  },
  {
    "name": "Item name example 2",
    "price": 100,
    "is_offer": true
  },
  {
    "name": "Item name example 3",
    "price": 100,
    "is_offer": true
  }
]

The objective of my micro example is to receive a list of Items (the same base class of the API example), do some processing (change price value by a fixed factor) and return that altered list.

this works:

@app.put("/items/{item_id}")
def create_item(item_id: int, items: List[Item]):    
    return {"total" : len(items)}

and i can iterate trough the list with

for item in items:

but when i try to return the list with

return {items}

i get "TypeError: unhashable type: 'list'" error.

is there a simple way to return the list? Or i'll need to create the return string manually?

WebSocket example is missing

Documentation states that FastAPI has support for WebSockets but there is no example on how to deal with it in code. Search on the internet is giving no results.

How to pass list in query parameters?

Description

I need to support several query parameters with same name in GET route. Typical request looks like this:
http://localhost/item?num=1&num=2

I configured a route

@app.get("/item", content_type=UJSONResponse)
async def get_part(num: list):
    found = False
    for i in num:
         if i in some_data:
             found = True
             break
    return {"found": found}

The idea is, that I can pass several numbers to check, if they exist in some_data. In my opinion, it is not a good idea to get numbers from body here, because it is a simple GET request, but in current version application expects argument "num" in body, so on my request (written above) I receive a response

{"detail":[{"loc":["body","num"],"msg":"field required","type":"value_error.missing"}]}

As I know, it is not restricted to pass several query parameters with the same name in an HTTP request by any specifications, so I would like to ask, is it possible to configure a route in FastAPI, which will be able to parse several query parameters with the same name?

accessing the request object

In starlette you can access request object in function decorated with the route decorator.

it seems very handy to be able to access middlewares etc,
is there a way in fastapi to do that using the provided get/post/options.... decorators?
same question for the ApiRouter.

@app.route("/notes", methods=["GET"])
async def list_notes(request):
    query = notes.select()
    results = await request.database.fetchall(query)

What is best way to override logging to use structlog?

Description

How can I [...]? I'm using structlog for logging in the application to get JSON logs (for loading into centralized logging service). The FastAPI/Starlette?/uvicorn logging is using standard text-based logging. What is the best way to override that to use my structlog configuration?

Additional context

Here is my structlog setup if that is useful:

import sys
import logging

import structlog
import structlog._frames


def logging_setup(settings):
    log_level = settings.LOGGING

    logging.basicConfig(format="%(message)s", stream=sys.stdout, level=log_level)
    logger = logging.getLogger()
    logger.setLevel(log_level)

    def add_app_context(logger, method_name, event_dict):
        f, name = structlog._frames._find_first_app_frame_and_name(["logging", __name__])
        event_dict["file"] = f.f_code.co_filename
        event_dict["line"] = f.f_lineno
        event_dict["function"] = f.f_code.co_name
        return event_dict

    structlog.configure(
        logger_factory=structlog.stdlib.LoggerFactory(),
        processors=[
            structlog.stdlib.filter_by_level,
            structlog.stdlib.add_logger_name,
            structlog.stdlib.add_log_level,
            add_app_context,
            structlog.processors.TimeStamper(fmt="iso"),
            structlog.processors.JSONRenderer(indent=2, sort_keys=True),
        ],
    )

I'm getting a mix of logging results:

pynanopubstore    | Checking for script in /app/prestart.sh
pynanopubstore    | There is no script /app/prestart.sh
pynanopubstore    | INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
pynanopubstore    | INFO: Started reloader process [1]
pynanopubstore    | 2019-03-12 19:05.17 Using config file: None
pynanopubstore    | HEAD http://dev.biodati.test:9200/nanopubstore [status:200 request:0.006s]
pynanopubstore    | Started server process [9]
pynanopubstore    | Waiting for application startup.


pynanopubstore    | ('172.18.0.5', 32940) - "GET /docs HTTP/1.1" 200
pynanopubstore    | ('172.18.0.5', 32940) - "GET /openapi.json HTTP/1.1" 200
pynanopubstore    | {
pynanopubstore    |   "doc_type": "nanopub",
pynanopubstore    |   "event": "will do ES search",
pynanopubstore    |   "file": "./services/search.py",
pynanopubstore    |   "from_": 0,
pynanopubstore    |   "function": "es_search",
pynanopubstore    |   "index": "nanopubstore",
pynanopubstore    |   "level": "info",
pynanopubstore    |   "line": 247,
pynanopubstore    |   "logger": "services.search",
pynanopubstore    |   "query": {
pynanopubstore    |     "query_string": {
pynanopubstore    |       "allow_leading_wildcard": true,
pynanopubstore    |       "default_field": "*",
pynanopubstore    |       "query": "this OR that"
pynanopubstore    |     }
pynanopubstore    |   },
pynanopubstore    |   "size": 50,
pynanopubstore    |   "timestamp": "2019-03-12T19:05:26.385863Z"
pynanopubstore    | }
pynanopubstore    | POST http://dev.biodati.test:9200/nanopubstore/nanopub/_search?size=50&from=0 [status:200 request:0.393s]
pynanopubstore    | ('172.18.0.5', 32940) - "POST /search HTTP/1.1" 200

Uvicorn 0.5

  • reloading now works programmaticaly. Not just when running uvicorn from the console.
  • Multi-worker support is available. (But not on by default)

Changes you'll want to make:

Switch the docs to uvicorn --reload instead of uvicorn --debug.

Debug tracebacks will be becoming strictly an application-level concern, and will disappear from uvicorn in a future version. If you want debug tracebacks, make sure you're using starlette's ServerErrorMiddleware, and switching it on or off appropriately depending on if FastAPI is running in a debug mode or not.

Recomended way to manage users?

Description

What is the best way to handle users registers, login, pasword changes, unregister?
A way to manage permissions and roles?
Additional context
Something similar to flask-auth , flask -security, flask login?

Use a default values for a request Swagger UI documentation

First of all, amazing project @tiangolo !

I have a quick question. I want the request body example in the Swagger UI documentation to represent some API calls the user would want to make. However, all I can see are the default values I have set in the BaseModel like "string" (see image). How do I change the examples in the documentation without changing the BaseModel? E.g. I wan't an user using the API to get another default value than the value you see in the Swagger documentation.

image

Security scopes

How can the scope parameter of the Security object be accessed?

Security accepts scopes as a parameter but the callable doesn't seem to be able to access it. The use case is essentially what is mentioned in the documentation - require certain scopes to be present to access an endpoint, or generate a 403 error.

What if you don't need the security parameter in the callback?

In the above use case, I'd like to require one of a set of scopes to be present but which one isn't really important. Using Security requires that a parameter be added like:

arg = Security(<callable>)

In callable(), test for the scopes and throw an HTTPException as needed. The problem is that arg isn't needed, so its ugly to pass it to the function. A much cleaner implementation would be to use a decorator - similar to the Starlette requires - like:

@requires(["user:read", "admin"])

Is this possible with the FastAPI design? If so, how does the decorate get passed a list of scopes (from the request)?

Streaming Large Files

I am working with this example in the documentation that shows a basic example of how to work with files.

Is it possible to stream a large file with this? What is the correct pattern?

It's possible to stream files with starlette, so how would integrating this functionality with fastapi work?

Thank you!

Docs for HTTP/2 support

Uvicorn is a great and fast HTTP/1 ASGI server that you recommend. I propose you recommend Hypercorn as a fast HTTP/2 ASGI server.

I'm the Hypercorn author, so naturally very biased. Also congratulations on the recognition of your great work.

graphql example

It would be useful to show how to accomplish integrating fastapi with graphene or another graphQL interface. Its touched on lightly in the docs, but I couldn't find a complete example that reuses the good parts of fastapi and pydantic.

Is this too far out of scope for a suggestion?

using external oAuth providers

Hi,

First of all, thank you for all the amazing work you've done with FastAPI. I'm just scratching the surface and I'm already amazed by what you're able to do right out of the box.

As for my question, At my institute we use a centralized authentication service for all webapps base on ORY Hydra. Is there an easy way built in to integrate an external server to authenticate again and use the token query the API?

Thanks
M

jsonable_encoder crash

Describe the bug

The jsonable_encoder crashes rightfully when passing a list of postgres Records, it's certainly a mis usage on my end, but I think that is something that would be interesting maybe to add in that function

Crash log
Connected to pydev debugger (build 183.5429.31)
backend_1_f0c43d42b730 | WARNING:root:email-validator not installed, email fields will be treated as str.
backend_1_f0c43d42b730 | To install, run: pip install email-validator
backend_1_f0c43d42b730 | DEBUG:app.app:postgresql://postgres:postgres@db:5432/fastapi_dev
backend_1_f0c43d42b730 | INFO:uvicorn:Started server process [1]
backend_1_f0c43d42b730 | INFO:uvicorn:Waiting for application startup.
backend_1_f0c43d42b730 | INFO:uvicorn:Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
backend_1_f0c43d42b730 | Traceback (most recent call last):
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 78, in jsonable_encoder
backend_1_f0c43d42b730 |     encoder = ENCODERS_BY_TYPE[type(obj)]
backend_1_f0c43d42b730 | KeyError: <class 'sqlalchemy.sql.base.ColumnCollection'>
backend_1_f0c43d42b730 | 
backend_1_f0c43d42b730 | During handling of the above exception, another exception occurred:
backend_1_f0c43d42b730 | 
backend_1_f0c43d42b730 | Traceback (most recent call last):
backend_1_f0c43d42b730 |   File "/opt/.pycharm_helpers/pydev/_pydevd_bundle/pydevd_trace_dispatch_regular.py", line 145, in __call__
backend_1_f0c43d42b730 |     if not is_stepping and cache_key in cache_skips:
backend_1_f0c43d42b730 | RecursionError: maximum recursion depth exceeded in comparison
backend_1_f0c43d42b730 | Fatal Python error: Cannot recover from stack overflow.
backend_1_f0c43d42b730 | 
backend_1_f0c43d42b730 | Thread 0x00007f5d9ffa9ae8 (most recent call first):
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/threading.py", line 300 in wait
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/threading.py", line 552 in wait
backend_1_f0c43d42b730 |   File "/opt/.pycharm_helpers/pydev/pydevd.py", line 128 in _on_run
backend_1_f0c43d42b730 |   File "/opt/.pycharm_helpers/pydev/_pydevd_bundle/pydevd_comm.py", line 320 in run
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/threading.py", line 917 in _bootstrap_inner
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/threading.py", line 885 in _bootstrap
backend_1_f0c43d42b730 | 
backend_1_f0c43d42b730 | Thread 0x00007f5da00acae8 (most recent call first):
backend_1_f0c43d42b730 |   File "/opt/.pycharm_helpers/pydev/_pydevd_bundle/pydevd_comm.py", line 382 in _on_run
backend_1_f0c43d42b730 |   File "/opt/.pycharm_helpers/pydev/_pydevd_bundle/pydevd_comm.py", line 320 in run
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/threading.py", line 917 in _bootstrap_inner
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/threading.py", line 885 in _bootstrap
backend_1_f0c43d42b730 | 
backend_1_f0c43d42b730 | Thread 0x00007f5da01afae8 (most recent call first):
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/threading.py", line 300 in wait
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/queue.py", line 179 in get
backend_1_f0c43d42b730 |   File "/opt/.pycharm_helpers/pydev/_pydevd_bundle/pydevd_comm.py", line 459 in _on_run
backend_1_f0c43d42b730 |   File "/opt/.pycharm_helpers/pydev/_pydevd_bundle/pydevd_comm.py", line 320 in run
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/threading.py", line 917 in _bootstrap_inner
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/threading.py", line 885 in _bootstrap
backend_1_f0c43d42b730 | 
backend_1_f0c43d42b730 | Current thread 0x00007f5da6097b88 (most recent call first):
backend_1_f0c43d42b730 |   File "/opt/.pycharm_helpers/pydev/_pydevd_bundle/pydevd_trace_dispatch_regular.py", line 145 in __call__
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/sql/operators.py", line 425 in __getitem__
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/sql/elements.py", line 707 in operate
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/sql/operators.py", line 432 in __getitem__
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 83 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 96 in jsonable_encoder
backend_1_f0c43d42b730 |   File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 54 in jsonable_encoder
backend_1_f0c43d42b730 |   ...
fastapi_appfactory_backend_1_f0c43d42b730 exited with code 139
Aborting on container exit...

To Reproduce

Here's my simple app, I want to test the databases package from starlette

import logging
from typing import List

from fastapi import FastAPI

from app import settings
from app.settings import database
from app.models import notes, NoteIn


logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

logger.debug(settings.DATABASE_URL)
app = FastAPI()

app.debug = settings.DEBUG


@app.on_event("startup")
async def startup():
    await database.connect()


@app.on_event("shutdown")
async def shutdown():
    await database.disconnect()


@app.get("/")
async def root():
    logger.debug(database)
    return {"message": "Hello World"}


@app.get("/notes", response_model=List[NoteIn])
async def list_notes():
    query = notes.select()
    results = await database.fetch_all(query)
    # content = [
    #     {"text": result["text"], "completed": result["completed"]} for result in results
    # ]
    # return content
    return results


@app.post("/notes")
async def add_note(note: NoteIn):
    query = notes.insert().values(**note.dict())
    await database.execute(query)
    return note

Should you want I may give you the full gitlab repo address that can reproduce it simply with a docker-compose, instead of copying all files :)

Expected behavior

If I return content instead of results in the list_notes route I got no problem, so that one workaround.
Another workaround is to return
return [r._row for r in results]
but i don't like much using private attributes

I got the feeling that results, being a list of databases.backends.postgres.Record it might be rightfully "parsed" by jsonable_encoder by adding another if isinstance(obj, blablabla): check

So maybe not a bug, but a possible enhancement ;)

when using DatabaseMiddleware, the fetchall method (note, no underscore in it) return a list of asyncpg.Records which the encoder parsed fine: results = await request.database.fetchall(query)

now we got a list of databases.backends.postgres.Record

Environment:

  • OS: debian buster
  • FastAPI Version [e.g. 0.3.0], get it with: 0.5.0
import fastapi
print(fastapi.__version__)
  • Python version, get it with: 3.7.2
python --version

Additional context
Add any other context about the problem here.

Contextmanager as dependency

Depends() works great, but does not support post-response cleanup. How about injecting from context managers? Taking the SQL Db example, it would not need middleware anymore:

from contextlib import contextmanager

@contextmanager
def db() -> Session:
    db_session = Session()
    try:
        yield db_session
    finally:
        db_session.close()

@app.get("/users/{user_id}")
def read_user(user_id: int, db_session: Session = Depends(db)):
    user = get_user(db_session, user_id=user_id)
    return user

Middlewares do the job and they have been there forever, but from the FastAPI idiomatic approach request.scope looks a bit of a "dumpster" - it's not known in advance what to expect there without examining middlware docs/code. Middlewares also need to take care not to step on each other. And finally, not all paths may need that request.scope.db. By supporting contextmanager injection, I believe code can be more idiomatic, and more efficient (e.g. because we'll only initialize Session() for requests that need it).

What do you think?

Implementation wise, I guess dependencies.utils.solve_dependencies needs to return ctxmgrs in addition to values and errors. Then during execution we can use either contextlib.ExitStack or contextlib.AsyncExitStack (the latter is Python 3.7 only though) to wrap the execution with.
Also, since a "thing" passed to Depends() can be both callable and context manager, may be it worth having new DependsContextMgr() class. And finally, I think there should be some type checking to make sure that only async context managers are injected into async request handlers and vise-versa.

I can work on a PR for this if the initiative is going to be accepted.

FastAPI debugging

Hello
I've seen on FastAPI documentation site, that it integrates nice with a VSCode.
Any hint on debugging an FastAPI application in VSCode? There are some exaple configrations for python projects, but unfortunately I'm not able to utilize these for FastAPI

Thanks
Olegas

Please include a crud generator or a tutorial on doing crud with vue.

Is your feature request related to a problem? Please describe.
In order to rapid development, A crud generator (front end) would be great.

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
It can be documentation about generating basic crud.

Additional context
I'm not sure wether this is within the framework scope, but I just want to get flask behind.
This, and user/permission management are maybe the only 2 things lacking. IMHO.

file uploads > 65536 characters, binary blobs/mp4s etc.

Hello there,

First, I have to say that I am really impressed by what you guys are doing here. Also, your docs are outstanding and easy to follow. I spotted your project on my recommendations page and immediately fell in love, losing most of my Friday night tinkering around.

When I got to your file upload section in the docs, I hit a snag when trying to upload an mp4 file.

{ "detail": [ { "loc": [ "body", "file" ], "msg": "ensure this value has at most 65536 characters", "type": "value_error.any_str.max_length", "ctx": { "limit_value": 65536 } } ] }
image

It seems like the File type expects bytes as strings, which aren't allowed to go past 65536 characters in length. I expect others might run into this too, or be confused like I am when hitting this part.

-Russell

ending / for collections

Is your feature request related to a problem? Please describe.

If we use the following option with sub-routes

app.include_router(search_router, prefix="/items") 

We are forced to have an ending '/' on the collection endpoints, e.g. /items/ vs /items/{id} This is I think the more formal REST practice, but it results in a 404 when someone uses /items instead - I'd rather follow the mantra of 'be flexible with regards to user input and strict with what I return'. I'd like to have the option of allowing both /items and /items/ for the collection endpoints.

Describe the solution you'd like

I'd be happier to have a single route documented and the other route just work. I do like the setup of the prefixing of sub-routes - that's really convenient and powerful. But, I need to have the /items collection route option which prefix'ing doesn't allow for.

Describe alternatives you've considered

I can provide an /items endpoint without using the prefix option. I don't know if there is a better way to handle this though. I also managed to add two route decorators to get both /items and /items/ working as endpoints and documented in Swagger - unfortunately Swagger doesn't support synonymous routes yet. I'd be happier to have a single route documented and the other route just work.

Additional context

https://take.ms/fkG7N

How use by_alias argument in jsonable_encoder

API that I'm implementing requires from me input and output in camel case style. But I want to use snake case in my python code and follow pep8. So I tried allow_population_by_alias in my config class from the pydantic model and it works as expected without fastapi. But in fastapi, I can get the right response only when I set by_alias in jsonable_encoder to true. Is it possible to use this argument somehow from route decorators? I know that pydantic docs says that it's bad practice to use allow_population_by_alias, but I don't know another way to implement the specification as I want. The best way will be to have in fastapi or pydantic decorator for auto-renaming fields like this in serde for rust, but it's not important for me now. I just want my code to pass these tests now:

import json
from typing import List

from fastapi import FastAPI
from pydantic import BaseModel, Schema

import pytest
from starlette.testclient import TestClient

app = FastAPI()


class Model(BaseModel):
    model_field: str = Schema(..., alias="modelField")

    class Config:
        allow_population_by_alias = True


@app.get("/models", response_model=List[Model])
def get_models():
    m = Model(model_field="string")
    return [
        Model(model_field=m.model_field),
        Model(modelField=m.model_field),
        Model(**m.dict()),
        Model(**m.dict(by_alias=True)),
    ]


@app.post("/models", response_model=Model)
def create_model(m: Model):
    return Model(**m.dict())


@pytest.fixture
def client():
    yield TestClient(app)


def test_get_models(client):
    with client:
        response = client.get("/models")
    assert response.json() == [{"modelField": "string"} for _ in range(4)]


def test_create_model(client):
    with client:
        response = client.post("/models", json.dumps({"modelField": "string"}))
    assert response.json() == {"modelField": "string"}

How can I return a 202 Accepted response for long running REST call?

Hope this is the right place for a question.

I have a REST API post request that does a lot of computation, /crunch. Rather than block the event loop I would like /crunch to return 202 Accepted status code along with a token string. Then the user of the API can call get request /result/{token} to check on the status of the computation. This is outlined nicely here for example.

Is it possible to modify the response status code, for example, similar to this approach in Sanic?

Returning sqlalchemy Data Model

Hello,

First, thanks for all your docker project generators as well as the fantastic documentation. They have been super useful in getting my project off the ground.

I've been following the sqlalchemy example at: https://fastapi.tiangolo.com/tutorial/sql-databases/.

I'm trying to return a sqlalchemy data model, but I am getting the following error:

Fatal Python error: Cannot recover from stack overflow.

Thread 0x00007f115f510700 (most recent call first):
  File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 78 in _worker
  File "/usr/local/lib/python3.7/threading.py", line 865 in run
  File "/usr/local/lib/python3.7/threading.py", line 917 in _bootstrap_inner
  File "/usr/local/lib/python3.7/threading.py", line 885 in _bootstrap

Current thread 0x00007f116c905700 (most recent call first):
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 834 in __getattr__
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 836 in __getattr__
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 190 in __getattr__
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 51 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 30 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 59 in jsonable_encoder
  File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 31 in <dictcomp>
  ...
INFO: Stopping reloader process [2468]

If I modify the fastapi specific code:
https://fastapi.tiangolo.com/tutorial/sql-databases/#create-your-fastapi-code

and parse the sqlalchemy response into a dictionary, it works fine:

@app.get("/users/{username}")
def read_user(username: str):
    user = get_user(username, db_session)
    user = {"name": user.id,  "email": user.email}
    return user

Thanks again. Been loving FastAPI so far.

Multiple response content types in one endpoint?

Description

How can I [...]?

I'm trying to figure out how to use one endpoint for multiple response content_types? I want to create an /export API endpoint and be able to dump (from memory) responses such as application/json, application/yaml or application/zip based on the content-type requested.

Everything I've seen so far is just for a single response type - though I've probably missed something because this is one of the best documented projects I've used.

Use third party class as property in pydantic schema

Describe the bug
I have a pydantic schema that needs a third party class (bson.objectid.ObjectID) as a property. For this reason I created a custom validator and encoder as per pydantic documentation.

Code

from bson.objectid import ObjectId
from pydantic import BaseModel
from pydantic import validators
from pydantic.errors import PydanticTypeError
from pydantic.utils import change_exception

class ObjectIdError(PydanticTypeError):
    msg_template = 'value is not a valid bson.objectid.ObjectId'

def object_id_validator(v) -> ObjectId:
    with change_exception(ObjectIdError, ValueError):
        v = ObjectId(v)
    return v

def get_validators() -> None:
    yield validators.not_none_validator
    yield object_id_validator

ObjectId.__get_validators__ = get_validators

def encode_object_id(object_id: ObjectId):
    return str(object_id)

class UserId(BaseModel):
    object_id: ObjectId = None

    class Config:
        json_encoders = {
            ObjectId: encode_object_id
        }

class User(UserId):
    email: str
    salt: str
    hashed_password: str

# Just for testing
user = User(object_id = ObjectId(), email="[email protected]", salt="12345678", hashed_password="letmein")
print(user.json())
# Outputs:
# {"object_id": "5c7e424225e2971c8c548a86", "email": "[email protected]", "salt": "12345678", "hashed_password": "letmein"}


As you can see at the bottom of the code, the serialization seems to work just fine. But when I use this schema as an argument (and/or response type) in API operations and then open the automatic documentation, I get presented with an error.

Code

from bson import ObjectId
from fastapi import FastAPI
from user import User, UserId

app = FastAPI()


@app.post("/user", tags=["user"], response_model=UserId)
def create_user(user: User):
    # Create user and return id
    print(user)
    return UserId(objectId=ObjectId())

Log

INFO: ('127.0.0.1', 2706) - "GET /openapi.json HTTP/1.1" 500
ERROR: Exception in ASGI application
Traceback (most recent call last):
  File "<project-path>\venv\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 373, in run_asgi
    result = await asgi(self.receive, self.send)
  File "<project-path>\venv\lib\site-packages\uvicorn\middleware\debug.py", line 83, in __call__
    raise exc from None
  File "<project-path>\venv\lib\site-packages\uvicorn\middleware\debug.py", line 80, in __call__
    await asgi(receive, self.send)
  File "<project-path>\venv\lib\site-packages\starlette\middleware\errors.py", line 125, in asgi
    raise exc from None
  File "<project-path>\venv\lib\site-packages\starlette\middleware\errors.py", line 103, in asgi
    await asgi(receive, _send)
  File "<project-path>\venv\lib\site-packages\starlette\exceptions.py", line 74, in app
    raise exc from None
  File "<project-path>\venv\lib\site-packages\starlette\exceptions.py", line 63, in app
    await instance(receive, sender)
  File "<project-path>\venv\lib\site-packages\starlette\routing.py", line 43, in awaitable
    response = await run_in_threadpool(func, request)
  File "<project-path>\venv\lib\site-packages\starlette\concurrency.py", line 24, in run_in_threadpool
    return await loop.run_in_executor(None, func, *args)
  File "C:\Program Files (x86)\Python37-32\lib\concurrent\futures\thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "<project-path>\venv\lib\site-packages\fastapi\applications.py", line 83, in <lambda>
    lambda req: JSONResponse(self.openapi()),
  File "<project-path>\venv\lib\site-packages\fastapi\applications.py", line 75, in openapi
    openapi_prefix=self.openapi_prefix,
  File "<project-path>\venv\lib\site-packages\fastapi\openapi\utils.py", line 230, in get_openapi
    flat_models=flat_models, model_name_map=model_name_map
  File "<project-path>\venv\lib\site-packages\fastapi\utils.py", line 45, in get_model_definitions
    model, model_name_map=model_name_map, ref_prefix=REF_PREFIX
  File "<project-path>\venv\lib\site-packages\pydantic\schema.py", line 461, in model_process_schema
    model, by_alias=by_alias, model_name_map=model_name_map, ref_prefix=ref_prefix
  File "<project-path>\venv\lib\site-packages\pydantic\schema.py", line 482, in model_type_schema
    f, by_alias=by_alias, model_name_map=model_name_map, ref_prefix=ref_prefix
  File "<project-path>\venv\lib\site-packages\pydantic\schema.py", line 238, in field_schema
    ref_prefix=ref_prefix,
  File "<project-path>\venv\lib\site-packages\pydantic\schema.py", line 440, in field_type_schema
    ref_prefix=ref_prefix,
  File "<project-path>\venv\lib\site-packages\pydantic\schema.py", line 643, in field_singleton_schema
    raise ValueError(f'Value not declarable with JSON Schema, field: {field}')
ValueError: Value not declarable with JSON Schema, field: object_id type=ObjectId default=None


To Reproduce
Copy my code and follow the instrcutions given in the "Describe the bug" section.

Expected behavior
No error should occur and the documentation should be able to show the schema correctly.

Environment:

  • OS: Windows 10
  • FastAPI: 0.6.3
  • Python: 3.7.2

Peewee usage

Description

How can I use peewee ORM with fastapi?

Additional context

I'd love to use peewee rather than sqlalchemy for my API. However, all documentation seems to be oriented to SQLAlchemy.

It seems like I can use peewee directly up to a certain point, however some stuff (like ForeignKey relations) don't really work by default.

Any plan to suppprt BackgroundTask from Starlette?

Starlette allows to attach a list of background tasks to a response, that will run only once the response has been sent.
If the task is a not a coroutine is it executed on a specific executor to not block the event loop.

    if task.is_coroutine():
        future = asyncio.ensure_future(task())
    else:
        loop = asyncio.get_event_loop()
        future = await loop.run_in_executor(None, task.func)

Is there any possibility to add this great feature to Fastai ?

Creating Enum class from dictionary

I want the user to be able to select parameter values from an enum list of values as a dropdown in the swagger documentation.

The only way, to my knowledge, to do that is to create a Enum pydantic class, and designate a parameter as a part of that class. Which is fine. But in my situation, I want the enum to be dynamically generated based on all unique document values of a property stored in a MongoDB collection. I think you can create a BaseModel class dynamically using the create_model() function, but as far as I know that's not possible with a Enum class.

So my question is: How can I create a parameter enumeration in Swagger from all values in a mongDb collection?

Storing object instances in the app context

Description

In Flask, I've found this to be a common pattern to do something like this:

run_app.py

from api.factory import create_app

app = create_app()

api/factory.py

from flask import Flask, current_app
import redis
import config
from api.resources.basic import basic

def create_app():
    """Create the app."""
    app = Flask(__name__)
    app.config.from_object(config.ProductionConfig)
    app.redis = redis.Redis(host=app.config["REDIS_HOST"], port=app.config["REDIS_PORT"])
    app.register_blueprint(basic, url_prefix="/api/v1")

api/resources/basic.py

from flask import current_app
from flask import Blueprint
from webargs import fields
from webargs.flaskparser import use_args

mod = Blueprint('basic', __name__)
write_args = {"value": fields.Str(required=True)}

@mod.route('/<str:key>', methods=['POST'])
@use_args(write_args, key)
def create_resource(args, key):
   """POST resource to redis."""
   current_app.redis.set(key, args["value"])
   current_app.logger.info("inserted value into redis")
   return {key: args["value"]}, 201

@mod.route('/<str:key>', methods=['GET'])
def retrieve_resource(key):
   """GET value from redis."""
   return {key: current_app.redis.get(key)}, 200

Is it possible to have a 'global' app context where you can put objects shared across request contexts, where you would access objects that you don't want to keep reinstantiating because it might be expensive and because of the convenience and how it makes it easier to reason about where 'objects' live. Like current_app.redis, or current_app.logger, or current_app.kafka_producer. I read about Depends, and saw the examples provided for how to deal with dependencies / resources but I didn't see something like the above.

Might be a bad practice, but it's worked well for me so far.

tags at APIRouter level

Is your feature request related to a problem? Please describe.
I have a certain number of APIRouter, with for each of those a certain number of routes.
I want all routes that belong to a given APIRouter to have the same tag, and currently I'm achieving this by adding tags=['Tag1'] to each and every route.

Describe the solution you'd like
I got the feeling that I should be able to add the tags keyword directly to APIRouter and that all routes belonging to it inherit the tag.

Not sure it makes sense though but I feel it would avoid some useless repetition

Response Model for Exceptions

This is a splinter conversation from #16

The docs for FastAPI say that you should raise an exception when an error occurs in your route logic, not return an object. Per #39, it seems like an elegant way to handle errors and I like it a lot.

In following with that pattern, I wonder if it is possible to extend the @app.exception_handler decorator to specify a Pydantic object that will be returned, the same way a standard @app.get decorator would? This might make the feature requested in #16 a little cleaner -- you could specify a list of codes that a route might throw, and the API documentation generator could figure it out from there.

Example code based on the suggestion:

from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
    name: str

class GenericHTTPError(BaseModel):
    status_code: int
    detail: str

items = [Item(name="foo"), Item(name='bar')]

app = FastAPI()

@app.get('/items/{item_id}', response_model=Item, errors=[404])
async def get_item(item_id: int):
    if item_id not in items:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item": items[item_id]}

@app.exception_handler(HTTPException, response_model=GenericHTTPError)
async def generic_error(request, ex):
    return GenericHTTPError(status_code=ex.status_code, detail=ex.detail)

I feel like I'm missing some details, but what do you think?

Clarify user_dict in Extra Models

Awesome project you have going on! Keep up the good work! ๐ŸŽ‰

I was reading through the docs and in the Extra Models section, the About **user_dict sub-section doesn't explain why there is a difference between using **user_dict vs **user_in.dict().

Also I wasn't sure if you meant to specify user_dict as a generic dictionary for the section as that object doesn't exist in the above code example, or did you mean to also continue to use user_in?

SQLAlchemy QueuePool limits

I'm trying to follow the SQLAlchemy part of the tutorial but I'm having problems because after several requests I'm running out of sessions. Clearly I should be closing them at some point, but I don't quite know how or when. This is also my first time using SQLAlchemy, so that doesn't help. :)

Should I be using the Starlette database middleware instead? If so, can I still integrate it with the nice SQLAlchemy models?

Updating pydantic

Is your feature request related to a problem? Please describe.

I need the ability to use the Extra.forbid config option to indicate when I have extra values in my pydantic model. This feature landed in v0.19.0 and was fixed/enhanced in v0.20.0. There appears to be one breaking change in v0.20.0 since v0.18.2 (which is what is currently locked for fastapi)

Describe the solution you'd like
I'd like to update to pydantic v0.20.0. I can generate a PR for this, but I'm not sure why you locked it at v0.18.2

isort config inconsistent between local and travis

Describe the bug
if you run isort locally, it sorts the fastapi package as a 3rd party package, so once you push a branch on travis, isort there will fail
I think PyCQA/isort#541 (comment) describes it well

To Reproduce

Expected behavior
to run isort locally and have travis succeed without having to change fastapi import orders

Environment:

  • OS: debian buster
  • FastAPI Version [e.g. 0.3.0], get it with: 0.5.0
import fastapi
print(fastapi.__version__)
  • Python version, get it with:
python --version

Additional context
Add any other context about the problem here.

Nesting FastAPI instances doesn't work very well

Do this:

main_app = FastAPI()
sub_api = FastAPI()

...
main_app.router.routes.append(Mount('/subapi', app=sub_api))

sub_api will correctly serve ever /subapi -- docs, methods, all that. However, the docs will still look for /openapi.json (absolute link) when trying to load the openapi spec. Additionally, the spec will not be adjusted to have the correct links, relative to where the module is mounted.

Perhaps this is a corner use case, but a lot of apps might have different collections of routes mounted in different subpaths.

openapi_url incorrect from behind reverse proxy

The use case:

I'm running FastAPI behind a nginx reverse proxy, at the path http://localhost/api/. The documentation front ends (swagger and redoc) are expecting openapi.json at http://localhost/openapi.json but it's actually routed at http://localhost/api/openapi.json.

Setting openapi_url to /api/openapi.json also changes the openapi.json path, so now it's looking for (through the proxy) http://localhost/api/api/openapi.json.

Ideally, it'd be great if we could specify the "public path" for the api. That's how e.g. vue does it

Check json_encoders in pydantic model

Thanks for your awesome project. It's really great!
I have a model with a datetime field that needs to be in ISO 8601 format in the response. And when I call json method from the model instance I get the right string, but the response from fastapi returns standart output:

from datetime import datetime, timezone

from fastapi import FastAPI
from pydantic import BaseModel


class ModelWithDatetimeField(BaseModel):
    dt_field: datetime

    class Config:
        json_encoders = {
            datetime: lambda dt: dt.replace(
                microsecond=0, tzinfo=timezone.utc
            ).isoformat()
        }


app = FastAPI()
model = ModelWithDatetimeField(dt_field=datetime.utcnow())


@app.get("/model")
def get_model():
    print(model.json())
    return model

So, in console I'll get right string representation:
{"dt_field": "2019-01-31T22:00:12+00:00"}

But in the response from server I'll get this:
{"dt_field": "2019-01-31T22:00:12.810220"}

Document test client

When switching from Flask / Flask_Restplus to FastAPI, tests fail
A basic test for a Flask RestPlus API will be like

class IntegrationTests(unittest.TestCase):
    def setUp(self):
        self.app = app.test_client()

    def test_base(self):
        response = self.app.get('/')
        self.assertEqual(response.status_code, 200)

but FastAPI don't have a test_client().

Solution
To have the tests pass, it would be nice, if FastAPI could provide a similar interface for Unittests (e.g. with Nose).

Trying to use Starlette DatabaseMiddleware

Greetings and congrats again for this amazingly well documented library, I'm happy Twitter made me discover this !

So I decided to dive a little bit into it, and I was in particular interested in the Starlette DatabaseMiddleware.

I then cloned the related test in Starlette and reworked it using FastAPI here: https://github.com/euri10/fastapi/blob/dbmiddleware/tests/test_dbmiddleware.py

so in this test we got:

  • one starlette instance of Starlette starlette=Starlette() that makes the very same tests as in the test_database mentionned aboveand

  • one fastapi instance of FastAPI fastapi=FastAPI(), whose routes have been adapted by me to take the new "framework" into account (mainly switching to app.get and app.post instead of app.route, making use of pydantic models etc,....)

Each instance is tested separately in a class, namely class TestStarletteStyle(): and class TestFastAPIStyle():

Obviously TestStarletteStyle passes like in the original file.
Interestingly if you change starlette=Starlette() to starlette=FastAPI() TestStarletteStyle passes also, which makes sense since if I got it correctly a fastapi.post is the same as a fastapi.route, methods=["POST"]

However TestFastAPIStyle fails at various points, all tests fails but not all asserts:

  • fails here as while the previous RuntimeError has been raised, the entry has been put in the database, while in the TestStarletteStyle the RuntimeError prevented this, is seems related to the rollback_on_shutdown=True that would not have been taken into account if i understand correctly, but take this with caution I'm brand new to your code and starlette's one.
  • fails here too, and looking at what we got in db (5 entries instead of 2 in the test) it seems also related to a rollback not made.
  • finally fails here too, and we got 6 entries in db instead of 1 tested, same intuition.

So there's seem to be something incorrect with the rollback setting, happy to dig further but you surely have ideas, if making a PR with my failing branch is ok let me know

Clarify run_in_threadpool magic

Good day,

First of all - many thanks for creating this project. Such a relief - you really nailed the proper amount of "batteries included". And docs are great - not a given thing for such a young project.

I'm studying SQL Database example where you note that SQLAlchemy is not compatible with async hence you configure path using def instead of async def. However this example raises and eyebrow because it should block the whole server while database is executing - only that it does not because the magic you do by running request handlers through threadpool unless they are co-routines.

While this magic is nice convenience, don't you think I can confuse users, particularly those who are less experienced with the whole sync/async co-existence semantics in Python world?

My bottom line is that IMHO it worth adding a clear "Unless you define your request handlers as coroutines FastAPI will run them them in separate thread" note in the "SQL Databases" and "Concurrency and async / await" chapters. What do you think?

Me coming from aiohttp is used to have non-async request handlers for simple methods that don't involve any IO and this magical FastAPI behavior, while useful, would've caused a performance penalty on those methods.

fastapi issue of swagger display ?

Description

I have a pydantic model with Enum and Union parameters, and while they both appear in Schema, in a post route they are not displayed in the Example edit section.
I hesitated to file a bug but I;d prefer to ask if that's something that's feasible first.

I was surprised and made a small exercice, take this model:

class DisplayMe(BaseModel):
    my_bool: bool
    my_float: float
    my_str: str
    my_int: int
    my_dict: dict
    # my_list: list
    # my_tuple: tuple
    # my_set: set
    # my_List_str: List[str]
    # my_tuple_str_int: Tuple[str, int]
    # my_dict_str_int: Dict[str, int]
    # my_union_str_int: Union[str, int]
    # my_enum: Enum
    my_emailstr: EmailStr
    my_name_email: NameEmail
    my_urlstr: UrlStr
    my_dsn: DSN
    my_bytes: bytes
    my_decimal: Decimal
    my_uuid1: UUID1
    my_uuid3: UUID3
    my_uuid4: UUID4
    my_uuid5: UUID5
    my_uuid: UUID
    my_filepath: FilePath
    my_directorypath: DirectoryPath
    my_path: Path
    my_datetime: datetime
    my_date: date

add this route:

@router.post("/testypes")
async def types(tt: DisplayMe):
    return tt

should you uncomment any of the pydantic types commented in the DisplayMe model above, then the Edit section is empty, there's nothing to edit.

But I can see them in schema, for instance on the below screen my_tuple is visible in the Schema:

Imgur

Now if I put them commented they are in the Edit section:
Imgur

question is : is it possible to have the commented pydantic types in the swagger edit section, I'm mostyl interested in Union and Enum in fact :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.