25

I want to retrieve a specific header from my API inside a function with fastAPI, but I can't found a solution for this.

In flask was simply: request.headers['your-header-name']

Why the hell with fastAPI is so complicated to do a simple thing like this?

Anyone know a solution to retrieve a header? Thanks :)

The decorator:

def token_required(f):
    @wraps(f)
    def decorator(*args, **kwargs):
        CONFIG = settings.read_config()
        token = None
        headers = Request.headers
        if "Authorization" in headers:
            auth_header = Request.headers
            token = auth_header
        elif not token:
            return {"Error": "Token is missing or incorrect header name"}, 401

        try:
            public_key = CONFIG["APPLICATION"]["PUBLIC_KEY"]
            claim = jwt.decode(token, public_key)
            claim.validate()
        except UnicodeDecodeError as err:
            return {"Error": f"An error occurred -> {err} check your token"}, 401

        return f(*args, **kwargs)

    return decorator

I need to read 'Authorization' header to check if exist or not.

funnydman
  • 9,083
  • 4
  • 40
  • 55
Melom
  • 400
  • 1
  • 5
  • 14

2 Answers2

39

It's pretty similar, you can do

from fastapi import FastAPI, Request


@app.get("/")
async def root(request: Request):
    my_header = request.headers.get('header-name')
    ...

NOTE: that it's lowercased

Example:

from fastapi import FastAPI, Request

app = FastAPI()


@app.get("/")
async def root(request: Request):
    my_header = request.headers.get('my-header')
    return {"message": my_header}

Now if you run this app with uvicorn on your localhost, you can try out sending a curl

curl -H "My-Header: test" -X GET http://localhost:8000

This will result in

{"message":"test"}

UPD:

if you need to access it in decorator you can use following


def token_required(func):
    @wraps(func)
    async def wrapper(*args, request: Request, **kwargs):
        my_header = request.headers.get('my-header')
        # my_header will be now available in decorator
        return await func(*args, request, **kwargs)
    return wrapper


ihoryam
  • 1,941
  • 2
  • 21
  • 24
  • Hi, I need to do this inside a decorator function. I'll update my question to clarify my problem – Melom Jul 02 '21 at 23:04
  • using middleware for this purpose doesn't suit your needs ? – ihoryam Jul 02 '21 at 23:27
  • anyways, I'll update my answer accordingly – ihoryam Jul 02 '21 at 23:30
  • I am converting a flask project to a fastAPI one, but in my flask project I was using the decorator on the paths I wanted them to be with authentication. I don't know how I can do the same thing but with fastAPI. – Melom Jul 02 '21 at 23:32
  • it might make sense for you to look into fast api middleware https://fastapi.tiangolo.com/tutorial/middleware/ Long story short you can use middleware to setup authentication in single function, but this would probably bring some complexity, since you'd either need to define two applications one for public routes and second for private. Easier way is using a decorator as you've mentioned, please check if update answer suits your needs – ihoryam Jul 02 '21 at 23:36
  • In that way decorator want a request value when I call it but if i pass inside him "Request" from fastAPI library return an error... I think I have to check how I can use middleware for two reasons. First: my decorator it seems unstable to me in fastAPI. Second: I want to follow the best practices for this framework. you confirm that middleware is the correct way to authenticate my private APIs, right? – Melom Jul 02 '21 at 23:50
  • This highly depends on your needs and weather you need to authenticate all routes or part of them. If it's only part of them, then take a look on dependencies https://fastapi.tiangolo.com/tutorial/dependencies, here's a nice example that covers authentication https://github.com/tiangolo/fastapi/issues/2037. If you need to authenticate all routes than you can use middleware – ihoryam Jul 03 '21 at 00:01
  • 1
    Yes, I have to authenticate only a part of them, not all routes. I will take a look to the links. Thank you ihoryam – Melom Jul 03 '21 at 00:07
  • I think it would be helpful to mention that request parameter can be used alongside with all other types of parameters. At least from the examples that wasn't obvious for me – Alleo Jan 01 '23 at 04:07
10

Or, as described in the fastapi documentation (https://fastapi.tiangolo.com/tutorial/header-params/):

from typing import Optional

from fastapi import FastAPI, Header

app = FastAPI()


@app.get("/items/")
async def read_items(user_agent: Optional[str] = Header(None)):
    return {"User-Agent": user_agent}

this will fetch the user_agent header parameter.

Valentin Dumitru
  • 185
  • 1
  • 10