CRUD operations with FastAPI REST API

Posted by


In this tutorial, we will be building a RESTful API using FastAPI that performs CRUD operations (Create, Read, Update, Delete) on a simple resource, such as a list of books. FastAPI is a modern, fast web framework for building APIs with Python.

To get started, you will need to have Python installed on your machine. You can install FastAPI and other required dependencies by running the following command:

pip install fastapi uvicorn

Next, we will create a new Python file named main.py where we will define our FastAPI application. Let’s start by importing the necessary modules:

from fastapi import FastAPI
from pydantic import BaseModel

Next, we will create an instance of the FastAPI class and define a basic route for testing:

app = FastAPI()

@app.get("/")
async def read_root():
    return {"message": "Hello, World!"}

You can run the FastAPI application using the following command:

uvicorn main:app --reload

You should see output indicating that the server is running, and you can access it by visiting http://127.0.0.1:8000 in your web browser.

Now let’s define a simple data model for our books resource using Pydantic:

class Book(BaseModel):
    title: str
    author: str

Next, we will create an in-memory database to store our books data:

books = []

We will now define the CRUD operations for our API. Let’s start with the Create operation:

@app.post("/books/")
async def create_book(book: Book):
    books.append(book)
    return book

This route accepts a POST request with JSON data representing a new book, creates a Book object from the data using Pydantic, appends it to the books list, and returns the newly created book.

Next, let’s define the Read operation to retrieve all books:

@app.get("/books/")
async def get_books():
    return books

This route returns all the books stored in the database.

Now let’s define the Update operation to update an existing book by its index:

@app.put("/books/{index}")
async def update_book(index: int, book: Book):
    if index < len(books):
        books[index] = book
        return book
    else:
        return {"error": "Book not found"}

This route accepts a PUT request with JSON data representing the updated book and the index of the book to update. If the index is valid, the corresponding book is updated and returned. Otherwise, an error message is returned.

Finally, let’s define the Delete operation to delete a book by its index:

@app.delete("/books/{index}")
async def delete_book(index: int):
    if index < len(books):
        deleted_book = books.pop(index)
        return deleted_book
    else:
        return {"error": "Book not found"}

This route accepts a DELETE request with the index of the book to delete. If the index is valid, the corresponding book is deleted and returned. Otherwise, an error message is returned.

That’s it! You have now created a basic CRUD API using FastAPI. You can test the API using a tool like Postman by sending requests to the relevant endpoints (e.g., http://127.0.0.1:8000/books/) with the appropriate HTTP method and data.

This tutorial covers the basic CRUD operations, but you can extend the API further by adding authentication, validation, error handling, pagination, and more advanced features. FastAPI provides excellent documentation and features to help you build powerful and efficient APIs with Python.

0 0 votes
Article Rating
42 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
@kvelez
2 months ago

from datetime import datetime

from typing import Text, Optional, List

from fastapi import FastAPI, HTTPException

from fastapi import Body

from pydantic import BaseModel, Field

from uuid import uuid4, UUID

class Post(BaseModel):

id: UUID = Field(default_factory=uuid4)

title: str

author: str

content: Text

created_at: datetime = Field(default_factory=datetime.now)

published_at: Optional[datetime] = None

published: bool = False

# Use a dictionary for in-memory database

posts_db: List[Post] = []

app = FastAPI()

@app.get("/")

async def main():

return {"message": "Hello World"}

@app.get("/posts/{post_id}", response_model=Post)

async def get_post(post_id: UUID):

for post in posts_db:

if post.id == post_id:

return post

raise HTTPException(status_code=404, detail="Post not found")

@app.get("/posts", response_model=List[Post])

async def get_posts():

return posts_db

@app.post("/posts", response_model=Post, tags=["posts"])

async def create_post(post: Post = Body(…)):

posts_db.append(post)

return post

@app.put("/posts/{post_id}", response_model=Post, tags=["posts"])

async def update_post(post_id: UUID, updated_post: Post = Body(…)):

for index, post in enumerate(posts_db):

if post.id == post_id:

updated_post.id = post_id # Ensure the ID remains the same

posts_db[index] = updated_post

return updated_post

raise HTTPException(status_code=404, detail="Post not found")

@app.delete("/posts/{post_id}", response_model=Post, tags=["posts"])

async def delete_post(post_id: UUID):

for index, post in enumerate(posts_db):

if post.id == post_id:

deleted_post = posts_db.pop(index)

return deleted_post

raise HTTPException(status_code=404, detail="Post not found")

@hannsflip
2 months ago

Gracias por la explicacion!!!

@kevinniebla1364
2 months ago

Los que le salga problema del 422 aunque lo tenga exactamente igual, se debe a que ahora tienes que definir Optional como None, id: Optional[str] = None y published_at : Optional[datetime] = None

@javierrivasseau8956
2 months ago

Hola Fazt como estas? Crees que es mejor Fast API + React + MongoDB que la tech MERN?

@diegosanabria695
2 months ago

A quienes les sale un error usando Optional al momento de hacer el post coloquen "= None" al final de cada Optional, puede ser por la version de Python 🤔. Esto permite que se hagan posts normalmente

@zasory
2 months ago

29:00 para los que tuvieron problemas en ese minuto finalmente di con la solucion , quizas en la version del profesor ermitira agregar el objeto (diccionario) como se lo permitia a el pero en versiones nuevas no y es que el esquema pide si o si datos y hay que especificar en case de que no, adjunto mi solución:

from fastapi import FastAPI

from pydantic import BaseModel #Modelo inicial, como van a lucir nuestros datos

from typing import Text, Optional

from datetime import datetime

from fastapi import HTTPException, status

from fastapi.encoders import jsonable_encoder

from uuid import uuid4 as uuid

app = FastAPI()

posts = []

# Post Model

class Post(BaseModel):

id: Optional[str] = None

title: str

author: str

content: Text

created_at: datetime = datetime.now()

published_at: Optional[datetime] = None

published: bool = False

@app.get('/')

def read_root():

return { "welcome":"welcome to my REST API" }

@app.get('/posts')

def get_posts():

return posts

@app.post('/posts')

def save_post(post : Post):

post.id = str(uuid())

post_dict = jsonable_encoder(post)

posts.append(post_dict)

return "recibido"

@tupapielrey3978
2 months ago

me trabe en la parte 29:00 me sigue saliendo error 422 help me

@jobadolfosalinashernandez265
2 months ago

Para Heroku me está pidiendo agregar un método de pago, tú cómo le hiciste para que no te cobrara?

@qwwrt8596
2 months ago

Buen video man, mejor que muchos cursos pagos

@hagoresumenes9224
2 months ago

-fazt ¿por que usas tab de 8 espacios?
-mis motivaciones van mas allá de tu entendimiento

@arthurblair6999
2 months ago

Buenas Fazt, como haces para recargar la consola? Yo le pico ctrl + c y vuelvo a ejecutar uvicorn app:app

@cristianezequiel815
2 months ago

Hola nesecito ayuda con el error 422 lo tengo igual que vos y no me deja hacer el post

@germanconil9475
2 months ago

Sin desperdicios !!! sos un crack!!!

@antoniopaz3575
2 months ago

FAZT muy buen video, la verdad siempre que busco algo que aprender, siempre estas tu, queria preguntarte, si puedes hacer un video sobre como hacer un CRUD con relaciones N:N con fastapi, o si ya hiciste un video que hables de ello, la verdad me ayudarias bastante, si cuentas con alguna comunidad de Fast API que me pueda ayudar, gracias de antemano, muy buenos videos

@Martin-vd6ux
2 months ago

Para los que no les deja utilizar el método post.dict(), utilicen post.model_dump() ya que post.dict() quedó obsoleto. Gracias por el video Fazt!

@nicoux9581
2 months ago

Muy bueno! Muchas gracias por compartir

@PonsianoDeLoor
2 months ago

muchas gracias Fazt un buen inicio con fastAPI

@VHSHORROR8
2 months ago

Hola video terminado-….heroku ya quito el metodo gratis o bueno de mi parte no lo encontre lo subire a github.. Gracias

@arnifuentes7055
2 months ago

Gracias Fazt!!!!

@eduardolopezcolmenero
2 months ago

Y este proyecto se podría deploy en serverless? Como a un lambda? O se tendría que desarrollar para lambda específicamente?