
Recap
In part one, I started building a database to use for a monthly budgeting application. We covered the installation of MongoDB, as well as some of the syntax differences. After installing, we created a database, our first collection, and also created a document to go inside of this Grocery collection.
In part two, we discussed more options surrounding collections, such as size limits and validations. Having learned the cap limit, we created a sample collection to test on, as well as test data. We also discussed how to insert multiple documents at a time. After this, the remaining collections were added: Entertainment, Utility, Rent, Insurance, and Emergency. We also added documents to each of these collections, then verified that they were all within our Receipts database.
Continuation
Now that we have our Mongo database and collections completed, we can move onto our API. For this, we will use Fastapi. The difference will be in how we introduce our collections. For my typical tables using MySQL, I usually use sqlalchemy to create a database object. However, with sqlalchemy we use the ORM (object-relational mapper) tool, which we cannot use with MongoDB. Mongo uses NoSQL, which would not work in the same way. Because of this, we will use a Python distribution called PyMongo. Because of this, the setup will not be the same as how we previously created our FastAPIs.
Installing pymongo
To get us started, we will need to install what will be needed for the API. FastAPI has already been installed, but we are using the new PyMongo distribution to run our code. To install, run:
sudo pip3 install pymongo
Now, we are ready to start setting up our endpoints.
Setting Up the Grocery Endpoint
First, we will create a file called storage.py to hold the functions to call. Recall, we will need to use async and await for the API. To start out the file, we will need to import the pymongo distribution:
import pymongo
Next, we will set up the connection. For this, we will need to create a Mongo based client, using the host containing the database and the port-specific to Mongodb. Next, we will select the database:
client = pymongo.MongoClient("localhost", 27017)
db = client.Receipts
After this, we can create our async function to get the Grocery documents. Much like with sqlalchemy, will return the results in a list. However, the ObjectID, which is the default primary key set in MongoDB, is not able to iterate. This is a big problem if we want to append this to a list. To get around this, we can reset the value to a string, which we would then only have the GUID value. This will need to be done within a for loop of all items in a select, which in Mongo would be a "find". Once the ObjectID is corrected, append it to the list we created. Next, close the database connection. Finally, return the list.
async def get_groceries():
GroceryList = []
for item in db.Grocery.find():
item["_id"] = str(item["_id"])
GroceryList.append(item)
client.close()
return GroceryList
With the function set up, we can now set up the endpoint. First, create the app.py file. Next, we will use several imports. Note, we may not use all just yet, but will need them in the future.
from fastapi import FastAPI
from typing import List
from pydantic import BaseModel
import storage
Next, set up the basics for FastAPI:
app = FastAPI (
title = "Receipts API",
description = "View receipts",
version = "1.0"
)
Now, we only need to create the endpoint. To do this, set the async function to get the grocery receipts. Then, set a variable that will await the results of what we set up in the storage file. Finally, return that variable.
@app.get("/receiptsapi/v1/grocery")
async def GetGrocery():
groceries = await storage.get_groceries()
return groceries
To test, we will be using uvicorn to run the app. If you don’t know already, uvicorn is an ASGI (Asynchronous Server Gateway Interface) server implementation, which allows us to create our Python framework. If you do not already have it installed, use:
sudo pip3 install uvicorn
Once it is installed, we can run the python app. I do this a little differently, like so:
uvicorn app:app –-reload –-host <HOSTNAME> --port <PORTNUMBER>
Note that the port number can be anything you want, but the hostname should have your app on it, in my case my Ubuntu IP address. Now, we are ready to test and should do so for every endpoint we create.

Setting Up the Emergency Endpoint
Having already set up the preliminaries in the first portion, we can move straight into coding the endpoint. It will follow the same format as the Grocery endpoint, just using different descriptive names. First, work on the storage.py file:
async def get_emergencies():
EmergencyList = []
for item in db.Emergency.find():
item["_id"] = str(item["_id"])
EmergencyList.append(item)
client.close()
return EmergencyList
Next, create the endpoint on the app.py file:
@app.get("/receiptsapi/v1/emergency")
async def GetEmergency():
emergencies = await storage.get_emergencies()
return emergencies
Now all you do is test:

Setting Up the Entertainment Endpoint
Now, we can set up the next endpoint. For this, we will follow the same steps. First, set up the storage.py file:
async def get_entertainment():
EntertainmentList = []
for item in db.Entertainment.find():
item["_id"] = str(item["_id"])
EntertainmentList.append(item)
client.close()
return EntertainmentList
Next, the app.py file endpoint:
@app.get("/receiptsapi/v1/entertainment")
async def GetEntertainment():
entertainment = await storage.get_entertainment()
return entertainment
Now to test:

Setting Up the Insurance Endpoint
I know this is getting repetitive but stick with me, we are almost there. Start with the storage.py file like before:
async def get_insurance():
InsuranceList = []
for item in db.Insurance.find():
item["_id"] = str(item["_id"])
InsuranceList.append(item)
client.close()
return InsuranceList
Next, the endpoint in the app.py file:
@app.get("/receiptsapi/v1/insurance")
async def GetInsurance():
insurance = await storage.get_insurance()
return insurance
Back to Postman to test:

Setting Up the Rent Endpoint
First, the storage.py file needs coding:
async def get_rent():
RentList = []
for item in db.Rent.find():
item["_id"] = str(item["_id"])
RentList.append(item)
client.close()
return RentList
Next, a little work on the app.py endpoint:
@app.get("/receiptsapi/v1/rent")
async def GetRent():
rent = await storage.get_rent()
return rent
Add now to test:

Setting Up the Utility Endpoint
Alright, last one. Add the following to the storage.py file:
async def get_utilities():
UtilityList = []
for item in db.Utility.find():
item["_id"] = str(item["_id"])
UtilityList.append(item)
client.close()
return UtilityList
Now for the last change in the app.py file:
@app.get("/receiptsapi/v1/utility")
async def GetUtility():
utilities = await storage.get_utilities()
return utilities
Finally, the last Postman test:

Recall, we can also look at our Swagger documentation:


Conclusion
Although it may have been repetitive, we were able to create an API for the monthly budget application. Because MongoDB uses NoSQL, we were unable to use the regular sqlalchemy. This is because, with sqlalchemy, we use the ORM tool, which is designed specifically for relational databases. As we learned in Part one, NoSQL does not use a relational model.
We were able to work around this issue by using pymongo, which allowed us to read for the collections. Although coding was very similar, we created different endpoints to read from each of the collections.
With the endpoints created, we were able to view the documents in our collections. Down the road, we can work on inserting, updating, and deleting. Until then, cheers!
References
https://pymongo.readthedocs.io/en/stable/
https://docs.mongodb.com/manual/reference/method/db.createUser/
https://realpython.com/introduction-to-mongodb-and-python/#mongodb