azure-functions-python-worker icon indicating copy to clipboard operation
azure-functions-python-worker copied to clipboard

Access /docs endpoint in FastAPI function apps

Open tonybaloney opened this issue 3 years ago • 20 comments
trafficstars

When deploying FastAPI using the ASGI worker,

The /docs endpoint only seems to work for "anonymous" functions. Is there anything I can do to use it with authlevel "function"?

Question asked by @pietz

tonybaloney avatar Aug 09 '22 04:08 tonybaloney

Any news on this issue?

hcs-bernardo-rufino avatar Sep 08 '22 23:09 hcs-bernardo-rufino

screenshot 2022-09-09 at 15 35 29

I've written a test app to recreate this. The main issue is that the docs site doesn't forward the code key to the openapi.json request.

There are a few solutions I can think of (the first is the most practical)

  1. Changing the auth to anonymous and using an authentication provider in FastAPI.

https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/

  1. Writing a swagger UI extension to forward the key https://fastapi.tiangolo.com/advanced/extending-openapi/#configuring-swagger-ui

This would only be the path if (1) is not possible.

tonybaloney avatar Sep 09 '22 06:09 tonybaloney

Try to allow Cross Origin Requests, see example here

See also this for documentation on auth levels for functions.

maurycyblaszczak-tj avatar Sep 22 '22 06:09 maurycyblaszczak-tj

thank you for your help.

@tonybaloney the auth option in fastapi is not something id want to do because i like the fact that azure is taking care of the authentication. its part of the service id like to use. the second suggested option is not something i was able to figure out.

@maurycyblaszczak-tj this looked most promising and i tried to implement it but failed. are you sure this works with functions? theres a good chance i was just too stupid to succeed.

pietz avatar Sep 23 '22 07:09 pietz

Have not tested it but something like this:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI(openapi_prefix="/api")  # adjust if you host at a different root

app.add_middleware(
    CORSMiddleware,
    allow_origins=['http://localhost:80'],  # protocol/address/port may be wrong, adjust if needed
    allow_methods=['GET'],
    allow_headers=['x-functions-key'],
 )

In order to work, this requires x-functions-key with the function key value to be send when you GET /docs.

maurycyblaszczak-tj avatar Sep 23 '22 07:09 maurycyblaszczak-tj

@maurycyblaszczak-tj Thanks again but setting the x-functions-key in the header instead of setting code in the url query is not really an option given that I want to open the /docs route in the browser.

I also found this thread but I fail to apply the changes to my Azure Function use case.

pietz avatar Sep 26 '22 11:09 pietz

I found a workaround that at least brings me to the docs page. however, trying out the API doesn't work this way for obvious reasons.

from fastapi.openapi.docs import get_swagger_ui_html

app = FastAPI(docs_url=None)

@app.get("/docs", include_in_schema=False)
async def get_docs(code: str):
    openapi_url = "/openapi.json?code=" + code
    return get_swagger_ui_html(openapi_url=openapi_url, title="docs")

pietz avatar Sep 26 '22 13:09 pietz

Thanks @pietz. Was able to make "try it out "work by including the code as a query argument in all the other endpoints as well. Didn't put effort into reducing the repeated and unused code query argument, but it works. And the documentation tells the user to provide it. Example:

@app.get("/")
def root(code: str = Query(..., description="Azure Function App key")):
    return {"message": "Hello World"}

Thyholt avatar Oct 14 '22 10:10 Thyholt

Hm, if the "try it out" isn't working, could the optional servers argument be useful here?

Discussion of it in the FastAPI docs: https://fastapi.tiangolo.com/advanced/behind-a-proxy/#additional-servers

pamelafox avatar Nov 14 '22 23:11 pamelafox

FYI, I've created a sample that puts an Azure API Management Policy in front of an authenticated Azure Function, passing along the function-key as part of the policy. I've also set it up such that the API calls require a subscription-key but the docs do not (by creating two "APIs" in APIM with two different policies).

Sample here: https://github.com/pamelafox/fastapi-azure-function-apim

I know this issue is about doing it entirely within FastAPI, but I think that does require more digging into FastAPI internals as you all have suggested, so I like this approach, plus APIM has some really neat policies you can add on top of the function (rate-limiting, e.g.)

pamelafox avatar Nov 21 '22 23:11 pamelafox