Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

FastAPI POST Requests

00:00 In this lesson, you’ll see how to implement the C in CRUD and create new items. But first you’ll need a database. Perhaps you’ve heard of the MEAN stack for web development.

00:12 And this is an acronym that stands for MongoDB, Express, Angular, and Node. There’s also the MERN stack that replaces Angular with React. If you add React and MongoDB to FastAPI, you get the FARM stack.

00:29 This course won’t be covering React, and it won’t go that in-depth into MongoDB, but here’s a crash course on how to quickly get started with MongoDB. So Mongo DB is a NoSQL database. TLDR, NoSQL means non-relational.

00:47 So instead of tables created by keys, MongoDB persists data in something called a document. The structure of a MongoDB database is a group of collections, and each collection is a group of documents.

01:00 Each document is conceptually a JSON object. The documents don’t have a schema, or at least it’s not required, so you can insert any JSON document into any collection.

01:11 That’s oversimplifying a real-world implementation a bit, but it is enough to get you started in this course. A real-world MongoDB database, just like a real-world relational database, lives on a server, and you have to connect to it via a network.

01:26 This can get tricky and be a hassle while developing. Thus for relational databases, many developers rely upon SQLite. This is a file-based database that doesn’t require the ceremony of connecting to a server.

01:40 You simply open a file to connect to the database. For MongoDB, there’s a file-based database called Mongita that you’ll use for the remainder of this course.

01:53 To install Mongita, use pip and install the mongita package.

02:03 Creating a Mongita database requires just a single line of code. You can create one on disk or in memory. This course will use the on-disk client. Import the MongitaClientDisk class from the mongita module in main.py.

02:20 Then create a new MongitaClientDisk instance. Now you can create a new database dynamically—I’ll call mine dband a new collection dynamically as well, which I’ll call shapes.

02:40 Be sure to remove the shapes list previously put into code to avoid conflicts.

02:52 To insert a new document, call the .insert_one() method with a dictionary. And to see the inserted document, get all the documents in the shapes collection with the .find() method on the collection. The dictionary here is a filter.

03:08 An empty dictionary means retrieve all documents in the collection. So how does this relate to FastAPI? Let’s take a look. You want to be able to insert a new shape into the database from the API, and that’s going to involve a POST request.

03:25 Just like the @get decorator you’ve seen up to this point, there is also a @post decorator. With a REST API, the data to create a new item is often included in the request body as JSON. As you’ve seen, the shape has a string name, integer number of sides, and finally an integer ID. To communicate this to FastAPI, you’ll use a pydantic base model.

03:49 So go ahead and import the BaseModel class from the pydantic module. Next, subclass BaseModel to create a Shape class.

04:02 Similar to a Django model, specify the properties of the shape, except use Python type hints.

04:12 The handler function for the post route will now accept a shape instance.

04:23 The .dict() method of the base model will return the data in a dictionary, and this dictionary can be used by Mongita to insert the document into the shapes collection in the database.

04:37 And finally, it is customary to return the newly created item in the body of a response from a POST request. Next, change the .get_shapes() method to remove the shape_id and return all of the documents in the shapes collection.

05:09 This code creates a dictionary for every document in the shapes collection. Since the object_id with key _id that Mongita assigns to the document cannot automatically be serialized to JSON, add an if clause to remove it. Real quick, before looking at Swagger, update the get_shape_by_id() function to work with Mongita. The decorator and signature will remain the same.

05:39 First, check for the number of documents with the specified id.

05:50 Use .find_one() to get the document and then create a dictionary from the document.

05:57 When a document is found, return it

06:06 and omit the _id key as it can’t be implicitly converted the JSON. And raise an exception if the document is not found. Time to look at Swagger. After the application restarts, expand the POST request for the /shapes endpoint and click the Try it out button. The Request body is a text area with a boilerplate JSON document. Fill it out with the details of a new shape.

06:41 The API will return a response with a 200 status code. The body will contain the JSON for the new shape. Switch to the command line and insert another document using HTTPie.

06:56 This command formats a JSON string from the key-value pairs in the body of the POST request. As mentioned earlier, the body of the POST request for a REST API has the JSON data for the item to create.

07:11 And you can see that a status of 200 is returned, along with the JSON for the new item in the body. So FastAPI serializes and deserializes the BaseModel subclasses to and from JSON for you, and also enforces the type hints for the model properties.

07:27 Pretty cool. Take one more look at the list of shapes in Mongita.

07:38 Whoops, a dodecagon has twelve, not fifteen, sides. But how can this error be resolved? You need a way to update existing items. And in the next lesson, you’ll learn how to do that.

Avatar image for Carlos Pumar-Frohberg

Carlos Pumar-Frohberg on Feb. 24, 2023

Thank you for this awesome intro to FastAPI! I am not able to render the POST-method as shown in the course:

#main_mongita.py

from fastapi import FastAPI, HTTPException
from mongita import MongitaClientDisk
from pydantic import BaseModel

class Shape(BaseModel):
    name: str
    no_of_sides: int
    id: int

app = FastAPI()

client = MongitaClientDisk()
db = client.db 
shapes = db.shapes

@app.get("/")
async def root():
    return {"message": "Hello world"}

@app.get("/shapes")
async def get_shapes():
    existing_shapes = shapes.find({})
    return [
        {key:shape[key] for key in shape if key != "_id"}
        for shape in existing_shapes
    ]

@app.get("/shapes/{shape_id}")
async def get_shape_by_id(shape_id: int):
    if shapes.count_documents({"id": shape_id}) > 0:
        shape = shapes.find_one({"id": shape_id})
        return {key:shape[key] for key in shape if key != "_id"}
    raise HTTPException(status_code=404, detail=f"No shape with id {shape_id} found")

@app.post("/shapes")
async def post_shape(shape: Shape):
    shapes.insert_one(shape.dict())
    return shape

The docs do not render the option for submitting a POST request. They only render the prior GET requests.

Could anyone please help to see what I am missing here?

Thx in advance!

Avatar image for danilolimadutra

danilolimadutra on March 17, 2024

Hi Carlos, I tried your code and all the endpoints are working fine. maybe you had some problem with the auto reload after changes.

Avatar image for sndselecta

sndselecta on Oct. 28, 2024

Irrelevant for course, I searched whether dodecagon was an actual term, and it was! Never heard of it before. Thank you. Quick correction: Dodecagon: 12 sides Pentadecagon: 15 sides

Become a Member to join the conversation.