azure-functions-python-worker
azure-functions-python-worker copied to clipboard
Access /docs endpoint in FastAPI function apps
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
Any news on this issue?
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)
- Changing the auth to anonymous and using an authentication provider in FastAPI.
https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/
- 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.
Try to allow Cross Origin Requests, see example here
See also this for documentation on auth levels for functions.
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.
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 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.
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")
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"}
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
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.)