steinitzu/fastapi-etag

Doesn't add etag when returning custom response

Closed this issue · 4 comments

lazka commented

I don't know what the solution here is, but in most cases I use TemplateResponse or JSONResponse, and in both cases no etags are added.

from typing import Any
from fastapi_etag import Etag, add_exception_handler
from fastapi import Depends, Request, FastAPI
from fastapi.responses import JSONResponse
from fastapi.testclient import TestClient

app = FastAPI()
add_exception_handler(app)


async def get_etag(request: Request) -> str:
    return "myetag"

@app.get('/foobar', dependencies=[Depends(Etag(get_etag))])
async def repos(request: Request) -> Any:
    return JSONResponse([])


client = TestClient(app)
r = client.get("/foobar")
print(r.headers)
lazka commented

I've solved this with a middleware for now:

def get_etag():
    return "foo"

@app.middleware("http")
async def add_etags_everywhere(request: Request, call_next: Callable) -> Response:
    etag = request.headers.get("if-none-match")
    current_etag = get_etag()
    if etag == current_etag:
        return Response("", 304, headers={"etag": current_etag})
    response: Response = await call_next(request)
    if "etag" not in response.headers:
        response.headers["etag"] = current_etag
    return response

The problem is that returning a response object from the route completely overrides any changes to the response made in the dependency chain.

You could add the headers from response dependency to your new response like this, should work:

app.get('/foobar', dependencies=[Depends(Etag(get_etag))])
async def repos(request: Request, response: Response) -> Any:
    return JSONResponse([], headers=response.headers)

But the middleware approach is probably better if you're adding etags the same way on every route

lazka commented

You could add the headers from response dependency to your new response like this, should work:

Thanks! I'll give that a try.

Feel free to close this (and maybe add this to the doc?, btw the examples in the docs don't work due to missing Depends usage and import)

But the middleware approach is probably better if you're adding etags the same way on every route

That sadly didn't work out because I hit fastapi/fastapi#1472

lazka commented

You could add the headers from response dependency to your new response like this, should work:

Thanks! I'll give that a try.

This worked nicely, thanks again