DEV Community

Cover image for Build A Laundry CRUD API with FastAPI using MongoDB - 1
Totoola Kenny
Totoola Kenny

Posted on

Build A Laundry CRUD API with FastAPI using MongoDB - 1

Building a Laundry CRUD API using FastAPI with the support of MongoDB as the database technology! I often use cloud storage like MongoDB in my projects to provide protection, the most reliable backups system, easy access to your data from anywhere, and most importantly is its low cost of access.

Table Of Contents

Grab your popcorn, sit comfortably and let's go 🚀

But wait... Do you have a basic knowledge using MongoDB? Have you written programs in Python? If YES!! Then you're a good fit to continue here. What if No! Don't Panic I got you covered by simplifying every single step in this article.

MongoDB??

Curious about what MongoDB is? or how it's being used?
MongoDB is a document-oriented database program which requires no SQL, and stores data in JSON-like formats.

FastAPI??

FastAPI is a modern, fast framework for building APIs with Python. Note that I had to bold the word fast! As the name implies "FastAPI", it is very fast and easy to code and automatically generates well swagger documentation for your API. That's sweet right! I know you will like this.

Get a drink and have a sip, Let's move 🚀

Basic CRUD in a Laundry API

A laundry service API should require the following basic CRUD(Create Read Update Delete) functions in managing bookings of services(laundry pickups, Updating status of service, canceling pickups, and so on).

Since this article is part one in building a laundry service API, we will focus on login/signup API endpoints(with no authentications yet).

Endpoints to be built in this article includes:

  • Login
  • signup
  • update-profile
  • book-service
  • update-pickup

Installing FastAPI

After highlighting the endpoints we're working on in this article, let's install FastAPI! You should have VSCode and your preferred browser ready(I use Chrome).

Firstly, open a folder(preferably on your desktop making it easy to locate), name it "laundryAPI".
Open the folder with VSCode and create a file "main.py"

Now open your VSCode Terminal and type this:
Note: You can create a virtual environment but not necessary
pip install fastapi

You will need an ASGI server for production such as Uvicorn:
pip install uvicorn

After successfully installing FastAPI, let's write our first API program for our root endpoint(homepage):
In the main.py, type the following code;

from typing import Optional

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def index():
    return {"message": "Hello World"}
Enter fullscreen mode Exit fullscreen mode

Let's run and test our API:
type this in the terminal to run the code;
uvicorn main:app --reload
Our API should be running on http://127.0.0.1:8000

We successfully built our API 🎉🎉

Setting up MongoDB Atlas

We successfully wrote our first FastAPI program! You see how fast and easy it is? Very fast!! I know you like that! Now, let's set up our MongoDB Atlas to store our laundry service data.

  • Signup for a free MongoDB cloud storage here
  • After signup, create a project, name it 'laundrystore'

You should see this now

  • Click build a cluster to create an Atlas:free atlas! New clusters take 1-3 minutes to provision
  • After the cluster has been created, click on 'connect' for details on how to connect your cloud storage to your app!
  • Set your cloud storage access permissions to allow connection from anywhere!
  • Set a database username and password, and choose a connection method!

Choose a connection Method

  • For this API, choose "Connect your application" and copy the connection string provided after selecting Python as the driver to use it!

Keep your connection string, we will use it in our API development! Do not forget your database username and password
We have successfully created and setup our MongoDB Atlas! We now have cloud storage for our Laundry API

Building each API Endpoints

Let's work on the endpoints highlighted for this part one article:
starting with the signup endpoint!

In this article, we will be using schematics to organize and validate our data model types and structures.

Install schematics:
pip install schematics

create a settings.py file and type the following code:

# MongoDB attributes
mongodb_uri = 'mongodb+srv://kenny:123CloudLaundry@cluster0.5xmt6.mongodb.net/<usersdata>?retryWrites=true&w=majority'
port = 8000
Enter fullscreen mode Exit fullscreen mode

Note that I replaced some strings in the connection string we copied from MongoDB with the database username and password we created

create a connection.py file and type the following code:

from pymongo import MongoClient
import settings

client = MongoClient(settings.mongodb_uri, settings.port)
db = client['usersdata']
Enter fullscreen mode Exit fullscreen mode

This is basically a connection file that creates a connection with MongoClient! Also, a database called 'usersdata'

Now, update your main.py file with the following code:

from typing import Optional

from fastapi import FastAPI
import connection
from bson import ObjectId
from schematics.models import Model
from schematics.types import StringType, EmailType


class User(Model):
    user_id = ObjectId()
    email = EmailType(required=True)
    name = StringType(required=True)
    password = StringType(required=True)

# An instance of class User
newuser = User()

# funtion to create and assign values to the instanse of class User created
def create_user(email, username, password):
    newuser.user_id = ObjectId()
    newuser.email = email
    newuser.name = username
    newuser.password = password
    return dict(newuser)

app = FastAPI()


# Our root endpoint
@app.get("/")
def index():
    return {"message": "Hello World"}

# Signup endpoint with the POST method
@app.post("/signup/{email}/{username}/{password}")
def signup(email, username: str, password: str):
    user_exists = False
    data = create_user(email, username, password)

    # Covert data to dict so it can be easily inserted to MongoDB
    dict(data)

    # Checks if an email exists from the collection of users
    if connection.db.users.find(
        {'email': data['email']}
        ).count() > 0:
        user_exists = True
        print("USer Exists")
        return {"message":"User Exists"}
    # If the email doesn't exist, create the user
    elif user_exists == False:
        connection.db.users.insert_one(data)
        return {"message":"User Created","email": data['email'], "name": data['name'], "pass": data['password']}
Enter fullscreen mode Exit fullscreen mode

-I will explain what we did there, but that is simply an implementation of the signup endpoint without hashing our password values!
-We will also learn how to hash our passwords before storing them into the cloud!
-The Signup endpoint simply creates a new user into the MongoDB storage and returns information about the user-created or either returns a piece of information that the user exists!

Type uvicorn main:app --reload to run the code!

Now visit http://127.0.0.1:8000/docs from your browser to use the FastAPI swagger UI to test our API.

This part one article is basically for us to learn for CRUD works and how it's being implemented! In the next article, we will learn how to professionally structure our code and folders! Professionally structuring our code simply means how to reuse codes! Qualities of a good program are the ability to reuse codes, class, functions, and so on.

Implementing the login endpoint: for the sake of python beginners, we're not using packages for our logins and signups!

Update your main.py file with the following code(updated with the login endpoint)

from typing import Optional

from fastapi import FastAPI
import connection
from bson import ObjectId
from json import dumps
from schematics.models import Model
from schematics.types import StringType, EmailType


class User(Model):
    user_id = ObjectId()
    email = EmailType(required=True)
    name = StringType(required=True)
    password = StringType(required=True)

# An instance of class User
newuser = User()

# funtion to create and assign values to the instanse of class User created
def create_user(email, username, password):
    newuser.user_id = ObjectId()
    newuser.email = email
    newuser.name = username
    newuser.password = password
    return dict(newuser)

# A method to check if the email parameter exists from the users database before validation of details
def email_exists(email):
    user_exist = True

    # counts the number of times the email exists, if it equals 0 it means the email doesn't exist in the database
    if connection.db.users.find(
        {'email': email}
    ).count() == 0:
        user_exist = False
        return user_exist

# Reads user details from database and ready for validation
def check_login_creds(email, password):
    if not email_exists(email):
        activeuser = connection.db.users.find(
            {'email': email}
        )
        for actuser in activeuser:
            actuser = dict(actuser)
            # Converted the user ObjectId to str! so this can be stored into a session(how login works)
            actuser['_id'] = str(actuser['_id'])    
            return actuser


app = FastAPI()


# Our root endpoint
@app.get("/")
def index():
    return {"message": "Hello World"}


# Signup endpoint with the POST method
@app.post("/signup/{email}/{username}/{password}")
def signup(email, username: str, password: str):
    user_exists = False
    data = create_user(email, username, password)

    # Covert data to dict so it can be easily inserted to MongoDB
    dict(data)

    # Checks if an email exists from the collection of users
    if connection.db.users.find(
        {'email': data['email']}
        ).count() > 0:
        user_exists = True
        print("USer Exists")
        return {"message":"User Exists"}
    # If the email doesn't exist, create the user
    elif user_exists == False:
        connection.db.users.insert_one(data)
        return {"message":"User Created","email": data['email'], "name": data['name'], "pass": data['password']}

# Login endpoint
@app.get("/login/{email}/{password}")
def login(email, password):
    def log_user_in(creds):
        if creds['email'] == email and creds['password'] == password:
            return {"message": creds['name'] + ' successfully logged in'}
        else:
            return {"message":"Invalid credentials!!"}
    # Read email from database to validate if user exists and checks if password matches
    logger = check_login_creds(email, password)
    if bool(logger) != True:
        if logger == None:
            logger = "Invalid Email"
            return {"message":logger}
    else:
        status = log_user_in(logger)
        return {"Info":status}
Enter fullscreen mode Exit fullscreen mode

-This code is instructing enough with the comments!
-The login endpoint uses the check_login_creds(), email_exists(), log_user_in() methods to: check if the user exists, then validates the users details and logs the user in if values matches

Tests Login Endpoint

The above image shows the result returned from the API when credentials for login isn't correct!
In the next article, we will also learn how to handle errors so our API doesn't break! for example when the connection to MongoDB is timed out, the API returns a 500 response code(application error)! It's more professional and advisable to use error handlings in codes so the application doesn't break!

Summary

In this article, we tried to make it as simplified as possible for every individual to understand!
No authentications, sessions, or any complicated method in building an API!
You can get the code here

Star the repo and follow me to!

Happy learning🎉🎉🎉

Top comments (2)

Collapse
 
rigelcarbajal profile image
Rigel Carbajal

Excelent, thanks so much.
I really want some example of a simple authentication and session haha =)

Collapse
 
anthlis profile image
Anthony L

Is a follow up article coming?