Last active
January 16, 2026 02:20
-
-
Save rhoboro/b2ee5b832f0557d65504b3220390ad8c to your computer and use it in GitHub Desktop.
FastAPI Minimal CRUD Template
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """FastAPI Minimal CRUD Template | |
| ```bash | |
| uv add 'fastapi[standard]' | |
| # Paste this file into main.py | |
| uv run fastapi dev | |
| ``` | |
| ```bash | |
| curl -X GET http://localhost:8000/api/todos | |
| curl -X GET http://localhost:8000/api/todos/N | |
| curl -X POST -H 'content-type: application/json' -d '{"title": "new todo"}' http://localhost:8000/api/todos | |
| curl -X PUT -H 'content-type: application/json' -d '{"title": "updated todo", "status": "IN_PROGRESS"}' http://localhost:8000/api/todos/N | |
| curl -X DELETE http://localhost:8000/api/todos/N | |
| ``` | |
| """ | |
| from enum import StrEnum | |
| from fastapi import FastAPI, status | |
| from fastapi.exceptions import HTTPException | |
| from pydantic import BaseModel as _BaseModel | |
| from pydantic import ConfigDict | |
| IN_MEMORY_DB: dict[int, Todo] = {} | |
| class Status(StrEnum): | |
| NEW = "NEW" | |
| IN_PROGRESS = "IN_PROGRESS" | |
| COMPLETED = "COMPLETED" | |
| class BaseModel(_BaseModel): | |
| model_config = ConfigDict(frozen=True) | |
| class Todo(BaseModel): | |
| id: int | |
| title: str | |
| status: Status | |
| class ListTodosResponse(BaseModel): | |
| todos: list[Todo] | |
| class CreateTodoRequest(BaseModel): | |
| title: str | |
| class UpdateTodoRequest(BaseModel): | |
| title: str | |
| status: Status | |
| app = FastAPI() | |
| @app.get("/") | |
| async def index() -> dict: | |
| return {"message": "hello"} | |
| @app.get("/api/todos") | |
| async def list_todos() -> ListTodosResponse: | |
| return ListTodosResponse(todos=[todo for todo in IN_MEMORY_DB.values()]) | |
| @app.post("/api/todos", status_code=status.HTTP_201_CREATED) | |
| async def create_todo(data: CreateTodoRequest) -> Todo: | |
| next_id = max(IN_MEMORY_DB) + 1 if IN_MEMORY_DB else 0 | |
| todo = Todo(id=next_id, title=data.title, status=Status.NEW) | |
| IN_MEMORY_DB[next_id] = todo | |
| return todo | |
| @app.get("/api/todos/{todo_id}") | |
| async def get_todo(todo_id: int) -> Todo: | |
| todo = IN_MEMORY_DB.get(todo_id, None) | |
| if not todo: | |
| raise HTTPException(404) | |
| return todo | |
| @app.put("/api/todos/{todo_id}") | |
| async def update_todo(todo_id: int, data: UpdateTodoRequest) -> Todo: | |
| todo = IN_MEMORY_DB.pop(todo_id, None) | |
| if not todo: | |
| raise HTTPException(404) | |
| new_todo = todo.model_copy(update=dict(title=data.title, status=data.status)) | |
| IN_MEMORY_DB[todo.id] = new_todo | |
| return new_todo | |
| @app.delete("/api/todos/{todo_id}", status_code=status.HTTP_204_NO_CONTENT) | |
| async def delete_todo(todo_id: int) -> None: | |
| if todo_id in IN_MEMORY_DB: | |
| del IN_MEMORY_DB[todo_id] | |
| return None |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment