Issue 1:
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.

Commit to Help

I commit to help with one of those options 👆

Example Code

from fastapi import FastAPI
from fastapi.responses import RedirectResponse
from starlette.middleware.sessions import SessionMiddleware
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware

app = FastAPI()

app.add_middleware(SessionMiddleware, secret_key="test secret key", https_only=False)
app.add_middleware(HTTPSRedirectMiddleware)

@app.get("/")
def read_root():
return RedirectResponse("/home")

Description

add breakpoints or print statements in HTTPSRedirectMiddleware.__init__

Run the app server. Your breakpoint will hit HTTPSRedirectMiddleware.__init__ more than once!

I'm trying to understand why fastapi/starlette re-initializes middleware IFF the user wants to add more than one middleware, as per my example.

I worked on a couple of other ideas to work around this:

I can see that instead of calling app.add_middleware... I could have also passed in a list of middlewares to the app, like so

from fastapi import FastAPI
from fastapi.middleware import Middleware
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
from starlette.middleware.sessions import SessionMiddleware

user_middlewares = []
user_middlewares.append(Middleware(HTTPSRedirectMiddleware))

user_middlewares.append(Middleware(SessionMiddleware, secret_key="test secret key", https_only=False))

app = FastAPI(middleware=user_middlewares)

The problem with this approach is that my custom middleware (not shown here as I'm using public ones) needs to have an instance of the FastAPI app passed in. That doesn't work in this case. I make that work in my current implementation by doing it like this

app = FastAPI()
app.add_middleware(MyCustomMiddleware, original_app=app)

which is my preferred option right now. But as mentioned above, since I'm adding multiple middleware by calling add_middleware twice, I don't want MyCustomMiddleware to be initialized twice!

My middleware is defined as follows (redacted for privacy):

from starlette.middleware.base import BaseHTTPMiddleware
class MyCustomMiddleware(BaseHTTPMiddleware):
def __init__(self, app: ASGIApp, original_app: FastAPI = None) -> None:
self.app = app
self.original_app = original_app
self.app_name = self.original_app.title

self.dispatch_func = self.dispatch_func
# other critical work that should only happen ONCE ever

async def dispatch_func(self, request: Request, call_next):
....
# work that relies on calling self.original_app.routes

I'm also aware that the fastapi way of adding middleware is with the @app.middleware("http") decorator described in the docs https://fastapi.tiangolo.com/tutorial/middleware/. However, As shown in MyCustomMiddleware implementation, I need it to be class-based for initialization and then for call_next later on

Is the multiple middleware initialization a design decision or an issue? Is there another way for me to design my CustomMiddleware, be able to add it and any other number of middleware to my app, but without having multiple initialization?

Operating System

Linux, macOS

Operating System Details

n/A

FastAPI Version

0.68.0

Python Version

3.9

Additional Context

No response

Issue 2:
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.

Commit to Help

I commit to help with one of those options 👆

Example Code

# TIP: This is full app. Run using `uvicorn main:app --port 5000 --reload`

from datetime import datetime
from typing import List

from fastapi import FastAPI
from pydantic import BaseModel

# Fake Data (database)

data = [
{
"id": 1,
"username": "johndoe007",
"created_at": datetime.now(),
"updated_at": datetime.now(),
}
]

# Pydantic
class DemoBase(BaseModel):
username: str

class DemoOut(DemoBase):
id: int
created_at: datetime
updated_at: datetime

# FastAPI
app = FastAPI()

@app.get("/", response_model=List[DemoOut])
def read_root():
return data

Description

If you visit the app you will get below response:

[
{
"username": "johndoe007",
"id": 1,
"created_at": "2021-09-13T12:57:55.200998",
"updated_at": "2021-09-13T12:57:55.201006"
}
]

It is working fine but the problem is when we want below:

1. order the data sent by response_model

In the above response, id is returned at 2nd position but I want to return at the 1st position. Requirement for this can be:

This is how I want my API to respond

As a full stack developer I directly render the response in the table and my id column is placed in 2nd column which should be in 1st row.

2. Update the data representation

In the above response, we get the date as 2021-09-13T12:57:55.200998 but I want to return the formatted date which should be human-readable. This is just a single example but there can be others as explained in this discussion.

Wanted Solution

I guess we can create another magic class that lets us define the field order and value representation but that might introduce code duplication. Sorry but I don't have any perfect solution.

Wanted Code

No idea

Alternatives

None. I might have to raise the same issue to pydantic.

Operating System

Linux

Operating System Details

Linux Mint 20.2 Cinnamon

FastAPI Version

0.68.0

Python Version

3.9.x

Additional Context

None