Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Building Python Microservices with FastAPI

You're reading from   Building Python Microservices with FastAPI Build secure, scalable, and structured Python microservices from design concepts to infrastructure

Arrow left icon
Product type Paperback
Published in Aug 2022
Publisher Packt
ISBN-13 9781803245966
Length 420 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Sherwin John C. Tragura Sherwin John C. Tragura
Author Profile Icon Sherwin John C. Tragura
Sherwin John C. Tragura
Arrow right icon
View More author details
Toc

Table of Contents (17) Chapters Close

Preface 1. Part 1: Application-Related Architectural Concepts for FastAPI microservice development
2. Chapter 1: Setting Up FastAPI for Starters FREE CHAPTER 3. Chapter 2: Exploring the Core Features 4. Chapter 3: Investigating Dependency Injection 5. Chapter 4: Building the Microservice Application 6. Part 2: Data-Centric and Communication-Focused Microservices Concerns and Issues
7. Chapter 5: Connecting to a Relational Database 8. Chapter 6: Using a Non-Relational Database 9. Chapter 7: Securing the REST APIs 10. Chapter 8: Creating Coroutines, Events, and Message-Driven Transactions 11. Part 3: Infrastructure-Related Issues, Numerical and Symbolic Computations, and Testing Microservices
12. Chapter 9: Utilizing Other Advanced Features 13. Chapter 10: Solving Numerical, Symbolic, and Graphical Problems 14. Chapter 11: Adding Other Microservice Features 15. Index 16. Other Books You May Enjoy

Designing and implementing REST APIs

The Representation State Transfer (REST) API makes up the rules, processes, and tools that allow interaction among microservices. These are method services that are identified and executed through their endpoint URLs. Nowadays, focusing on API methods before building a whole application is one of the most popular and effective microservices design strategies. This approach, called an API-first microservices development, focuses first on the client’s needs and then later identifies what API service methods we need to implement for these client requirements.

In our online academic discussion forum app, software functionality such as user sign-up, login, profile management, message posting, and managing post replies are some of the crucial needs we prioritized. In a FastAPI framework, these features are implemented as services using functions that are defined using Python’s def keyword, with the association of the appropriate HTTP request method through the path operations provided by @app.

The login service, which requires username and password request parameters from the user, is implemented as a GET API method:

@app.get("/ch01/login/")
def login(username: str, password: str):
    if valid_users.get(username) == None:
        return {"message": "user does not exist"}
    else:
        user = valid_users.get(username)
        if checkpw(password.encode(), 
                   user.passphrase.encode()):
            return user
        else:
            return {"message": "invalid user"}

This login service uses bcrypt’s checkpw() function to check whether the password of the user is valid. Conversely, the sign-up service, which also requires user credentials from the client in the form of request parameters, is created as a POST API method:

@app.post("/ch01/login/signup")
def signup(uname: str, passwd: str):
    if (uname == None and passwd == None):
        return {"message": "invalid user"}
    elif not valid_users.get(uname) == None:
        return {"message": "user exists"}
    else:
        user = User(username=uname, password=passwd)
        pending_users[uname] = user
        return user

Among the profile management services, the following update_profile() service serves as a PUT API service, which requires the user to use an entirely new model object for profile information replacement and the client’s username to serve as the key:

@app.put("/ch01/account/profile/update/{username}")
def update_profile(username: str, id: UUID, 
                     new_profile: UserProfile):
    if valid_users.get(username) == None:
        return {"message": "user does not exist"}
    else:
        user = valid_users.get(username)
        if user.id == id:
            valid_profiles[username] = new_profile
            return {"message": "successfully updated"}
        else:
            return {"message": "user does not exist"}

Not all services that carry out updates are PUT API methods, such as the following update_profile_name() service, which only requires the user to submit a new first name, last name, and middle initial for partial replacement of a client’s profile. This HTTP request, which is handier and more lightweight than a full-blown PUT method, only requires a PATCH action:

@app.patch("/ch01/account/profile/update/names/{username}")
def update_profile_names(username: str, id: UUID, 
                          new_names: Dict[str, str]):
    if valid_users.get(username) == None:
        return {"message": "user does not exist"}
    elif new_names == None:
        return {"message": "new names are required"}
    else:
        user = valid_users.get(username)
        if user.id == id:
            profile = valid_profiles[username]
            profile.firstname = new_names['fname']
            profile.lastname = new_names['lname']
            profile.middle_initial = new_names['mi']
            valid_profiles[username] = profile
            return {"message": "successfully updated"}
        else:
            return {"message": "user does not exist"}

The last essential HTTP services that we included before building the application are the DELETE API methods. We use these services to delete records or information given a unique identification, such as username and a hashed id. An example is the following delete_post_discussion() service that allows a user to delete a posted discussion when given a username and the UUID (Universally Unique Identifier) of the posted message:

@app.delete("/ch01/discussion/posts/remove/{username}")
def delete_discussion(username: str, id: UUID):
    if valid_users.get(username) == None:
        return {"message": "user does not exist"}
    elif discussion_posts.get(id) == None:
        return {"message": "post does not exist"}
    else:
        del discussion_posts[id] 
        return {"message": "main post deleted"}

All path operations require a unique endpoint URL in the str format. A good practice is to start all URLs with the same top-level base path, such as /ch01, and then differ when reaching their respective subdirectories. After running the uvicorn server, we can check and validate whether all our URLs are valid and running by accessing the documentation URL, http://localhost:8000/docs. This path will show us a OpenAPI dashboard, as shown in Figure 1.2, listing all the API methods created for the application. Discussions on the OpenAPI will be covered in Chapter 9, Utilizing Other Advanced Features.

Figure 1.2 – A Swagger OpenAPI dashboard

Figure 1.2 – A Swagger OpenAPI dashboard

After creating the endpoint services, let us scrutinize how FastAPI manages its incoming request body and the outgoing response.

You have been reading a chapter from
Building Python Microservices with FastAPI
Published in: Aug 2022
Publisher: Packt
ISBN-13: 9781803245966
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image