# APIRouter

When the number of endpoints increases in your API, it might be useful to split these endpoints up into seperate files, grouping endpoints based on functionality, data source, etc.

Splitting up your endpoints into seperate files can be achieved using the APIRouter class of FastAPI.

For the explanation about how this all works, we will start with the files you can find in the APIRouter example start (opens new window) repository.

In the main.py file of the repository mentioned above, we can find 4 endpoints, of which 3 GET request endpoints and 1 POST request endpoint. In the example below, we will split up these endpoints into two files. One file containing all GET request endpoints and another file for our POST request endpoint.

Right now, our file structure is as follows:

📂myproject
├── 📄.env (you should create the .env file yourself, it is not included in the repository)
├── 📄config.py
├── 📄database.py
├── 📄main.py
├── 📂models
|   └── 📄models.py
└── 📂queries
    └── 📄festival_queries.py
1
2
3
4
5
6
7
8
9

After implementing the APIRouter to split up our endpoints into multiple files, our file structure will look like this:










 
 
 

📂myproject
├── 📄.env
├── 📄config.py
├── 📄database.py
├── 📄main.py
├── 📂models
|   └── 📄models.py
├── 📂queries
|   └── 📄festival_queries.py
└── 📂routes
    ├── 📄get_endpoints.py
    └── 📄post_endpoints.py
1
2
3
4
5
6
7
8
9
10
11
12

# Creating files in the routes folder

Let's make the necessary changes and add a routes folder and the files get_endpoints.py and post_endpoints.py in it. As their names already suggest, they will contain either GET or POST requests. Please note that this is an example to demonstrate how endpoints can be spread over multiple files. You don't necessarily need to devide them based on the request type, you might as well split them up based on their functionality for example.

The basic structure of these files will be nearly the same as our current main.py file, with the main difference being that we will not create a FastAPI instance anymore. Instead, we will use an APIRouter instance.

The file get_endpoints.py will contain the following code:

 



 













































from fastapi import APIRouter
import database
from queries import festival_queries as queries

app = APIRouter()

@app.get("/festivals")
def get_all_festivals():
    query = queries.festival_name_query
    festivals = database.execute_sql_query(query)
    if isinstance(festivals, Exception):
        return festivals, 500
    festivals_to_return = []
    for festival in festivals:
        festivals_to_return.append(festival[0])
    return({'festivals': festivals_to_return})

@app.get("/province")
def get_all_festivals_by_province(name: str):
    query = queries.festivals_by_province_query
    festivals = database.execute_sql_query(query, (
        name,
    ))
    if isinstance(festivals, Exception):
        return festivals, 500
    festivals_to_return = []
    for festival in festivals:
        festivals_to_return.append(festival[0])
    return({'festivals': festivals_to_return})

@app.get("/name_and_month")
def get_all_festivals_by_name_and_month(name: str, month: int):
    query = queries.festivals_by_name_and_month_query
    festivals = database.execute_sql_query(query, (
        '%{}%'.format(name),
        month,
        month,
    ))
    if isinstance(festivals, Exception):
        return festivals, 500
    festivals_to_return = []
    for festival in festivals:
        location = festival[1] + ' (' + festival[4] + ')'
        festival_dictionary = {"name": festival[0],
                               "startDate": festival[2],
                               "endDate": festival[3],
                               "location": location }
        festivals_to_return.append(festival_dictionary)
    return({'festivals': festivals_to_return})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

We have basically cut the GET endpoints and imports from main.py and pasted them in get_endpoints.py. An important difference however is that we worked with the APIRouter class instead of the FastAPI class, as highlighted in the code above.

We will do the same for the remaining POST request and paste it in post_endpoints.py, just like the necessary imports:

 




 















from fastapi import APIRouter
import database
from models import models
from queries import festival_queries as queries

app = APIRouter()

@app.post("/festival")
def create_festival(festival: models.Festival):
    query = queries.insert_festival_query
    success = database.execute_sql_query(query, (
        festival.name,
        festival.location,
        festival.startDate,
        festival.endDate,
        festival.province,
        festival.comment,
    ))
    if success:
        return festival
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# Including the files with endpoints in main.py

In main.py we now need to indicate that the endpoints of the files get_endpoints.py and post_endpoints.py should be part of our API. We can do this using the include_router() function. As value of the router parameter of this function, we should pass the APIRouter instance of the file containing our endpoints. When doing so, don't forget to first import this file (or files in this case).

This is how we do it:




 



 
 











from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import config
from routes import get_endpoints, post_endpoints

app = FastAPI(docs_url=config.documentation_url)

app.include_router(router=get_endpoints.app)
app.include_router(router=post_endpoints.app)

origins = config.cors_origins.split(",")

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Add a prefix

If desired, it is possible to add a prefix to the endpoints coming from a certain file. If you want to add a prefix, add the prefix parameter to the include_router() function as shown below.








 
 











from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import config
from routes import get_endpoints, post_endpoints

app = FastAPI(docs_url=config.documentation_url)

app.include_router(router=get_endpoints.app, prefix="/get")
app.include_router(router=post_endpoints.app, prefix="/post")

origins = config.cors_origins.split(",")

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

The result of this addition is that the /festivals endpoint in get_endpoints.py should now be addressed as follows:

http://127.0.0.1:8000/get/festivals (opens new window)

Instead of using the 'normal' URL without prefix:

http://127.0.0.1:8000/festivals (opens new window)

Last Updated: 3/5/2024, 1:48:07 PM