8

I want to define a dict variable once, generated from a text file, and use it to answer to API requests.

This variable should be always available till the end of server run.

In an example below:

from fastapi import FastAPI
import uvicorn

app = FastAPI()

def init_data(path):
    print("init call")
    data = {}
    data[1] = "123"
    data[2] = "abc"
    return data

data = init_data('path')

@app.get('/')
def example_method():
    # data is defined
    return {'Data': data[1]}

if __name__ == '__main__':
    uvicorn.run(f'example_trouble:app', host='localhost', port=8000)

I will get:

init call
init call
INFO:     Started server process [9356]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://localhost:8000 (Press CTRL+C to quit)

and request to localhost:8000 wouldn't raise any errors

How should I define a variable once, that would be accessed as a global variable to any request? Is there a common way to define it once and use it?

requirements if necessary:

fastapi==0.68.1
pydantic==1.8.2
starlette==0.14.2
typing-extensions==3.10.0.2

2 Answers2

6

One approach would be to use the FastAPI startup event to define the variable data once on app startup.

An example similar to what you provided in your question:

from fastapi import FastAPI
import uvicorn

app = FastAPI()
data = {}

@app.on_event('startup')
def init_data():
    print("init call")
    path='/an/example/path'
    data[1] = "123"
    data[2] = "abc"
    return data

@app.get('/')
def example_method():
    # data is defined
    return {'Data': data[1]}

if __name__ == '__main__':
    uvicorn.run(f'example_trouble:app', host='localhost', port=8000)

When running the app, you'll see that function is only executed once:

INFO:     Started server process [37992]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
init call
Josh
  • 1,556
  • 1
  • 10
  • 21
  • 1
    It almost works. I changed "data = {}" to "global data" and defined global variable in init_data(). In this example, data variable is redefined to an Empty dict again after init_data method call – Alexander Lipatov Sep 07 '21 at 09:15
  • can you define global variables inside the startup loop instead of creating a data object? What would be the pros / cons of that approach? – dataviews Jan 22 '23 at 22:24
2

The current recommended approach to this in FastAPI is lifespans. Here's an example (untested):

from contextlib import asynccontextmanager
from fastapi import FastAPI

data = {}

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Init
    print("Startup")
    data["path"] = '/an/example/path'
    data[1] = "123"
    data[2] = "abc"

    yield

    # Shutdown
    print("Shutdown")
    data.clear()

app = FastAPI(lifespan=lifespan)

@app.get('/')
def example_method():
    # data is defined
    return {'data': data[1]}
jamix
  • 5,484
  • 5
  • 26
  • 35