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.
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")
Gracias por la explicacion!!!
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
Hola Fazt como estas? Crees que es mejor Fast API + React + MongoDB que la tech MERN?
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
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"
me trabe en la parte 29:00 me sigue saliendo error 422 help me
Para Heroku me está pidiendo agregar un método de pago, tú cómo le hiciste para que no te cobrara?
Buen video man, mejor que muchos cursos pagos
-fazt ¿por que usas tab de 8 espacios?
-mis motivaciones van mas allá de tu entendimiento
Buenas Fazt, como haces para recargar la consola? Yo le pico ctrl + c y vuelvo a ejecutar uvicorn app:app
Hola nesecito ayuda con el error 422 lo tengo igual que vos y no me deja hacer el post
Sin desperdicios !!! sos un crack!!!
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
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!
Muy bueno! Muchas gracias por compartir
muchas gracias Fazt un buen inicio con fastAPI
Hola video terminado-….heroku ya quito el metodo gratis o bueno de mi parte no lo encontre lo subire a github.. Gracias
Gracias Fazt!!!!
Y este proyecto se podría deploy en serverless? Como a un lambda? O se tendría que desarrollar para lambda específicamente?