Complete Todo application implementation
- Update database path configuration - Add test script for API functionality - Update README with testing instructions - Add requests package to requirements generated with BackendIM... (backend.im)
This commit is contained in:
parent
e852047583
commit
6da81ed97c
12
README.md
12
README.md
@ -9,6 +9,7 @@ A simple Todo application built with FastAPI and SQLite.
|
||||
- Database migrations with Alembic
|
||||
- Health check endpoint
|
||||
- OpenAPI documentation
|
||||
- Test script for API functionality
|
||||
|
||||
## Project Structure
|
||||
|
||||
@ -32,6 +33,7 @@ todoapplication/
|
||||
├── alembic.ini # Alembic configuration
|
||||
├── main.py # Application entry point
|
||||
├── requirements.txt # Python dependencies
|
||||
├── test_api.py # API testing script
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
@ -81,3 +83,13 @@ Create a new migration:
|
||||
```bash
|
||||
alembic revision -m "your migration message"
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
Run the API tests (make sure the server is running first):
|
||||
|
||||
```bash
|
||||
python test_api.py
|
||||
```
|
||||
|
||||
This will test all the CRUD operations for the Todo API.
|
||||
|
@ -1,15 +1,17 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
class Settings(BaseModel):
|
||||
API_V1_STR: str = "/api/v1"
|
||||
PROJECT_NAME: str = "Todo API"
|
||||
PROJECT_DESCRIPTION: str = "A simple Todo API built with FastAPI and SQLite"
|
||||
VERSION: str = "0.1.0"
|
||||
|
||||
|
||||
# Database settings
|
||||
DB_DIR: Path = Path("/app") / "storage" / "db"
|
||||
BASE_DIR: Path = Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
DB_DIR: Path = BASE_DIR / "storage" / "db"
|
||||
SQLALCHEMY_DATABASE_URL: Optional[str] = None
|
||||
|
||||
class Config:
|
||||
|
@ -4,4 +4,5 @@ sqlalchemy==2.0.27
|
||||
pydantic==2.5.3
|
||||
alembic==1.12.1
|
||||
python-dotenv==1.0.0
|
||||
pathlib==1.0.1
|
||||
pathlib==1.0.1
|
||||
requests==2.31.0
|
151
test_api.py
Normal file
151
test_api.py
Normal file
@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for the Todo API
|
||||
This script tests all the CRUD operations for the Todo API
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import sys
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
BASE_URL = "http://localhost:8000/api/v1"
|
||||
|
||||
def print_success(message: str) -> None:
|
||||
"""Print a success message in green color"""
|
||||
print(f"\033[92m✓ {message}\033[0m")
|
||||
|
||||
def print_error(message: str) -> None:
|
||||
"""Print an error message in red color"""
|
||||
print(f"\033[91m✗ {message}\033[0m")
|
||||
|
||||
def print_info(message: str) -> None:
|
||||
"""Print an info message in blue color"""
|
||||
print(f"\033[94m• {message}\033[0m")
|
||||
|
||||
def test_health_endpoint() -> bool:
|
||||
"""Test the health endpoint"""
|
||||
print_info("Testing health endpoint...")
|
||||
try:
|
||||
response = requests.get("http://localhost:8000/health")
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data.get("status") == "healthy":
|
||||
print_success("Health endpoint is working")
|
||||
return True
|
||||
else:
|
||||
print_error(f"Health endpoint returned unexpected data: {data}")
|
||||
return False
|
||||
else:
|
||||
print_error(f"Health endpoint returned status code {response.status_code}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print_error(f"Error testing health endpoint: {e}")
|
||||
return False
|
||||
|
||||
def create_todo(title: str, description: Optional[str] = None, completed: bool = False) -> Dict[str, Any]:
|
||||
"""Create a new todo and return the created todo data"""
|
||||
print_info(f"Creating todo: {title}")
|
||||
todo_data = {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"completed": completed
|
||||
}
|
||||
|
||||
response = requests.post(f"{BASE_URL}/todos/", json=todo_data)
|
||||
if response.status_code == 201:
|
||||
todo = response.json()
|
||||
print_success(f"Todo created with ID: {todo['id']}")
|
||||
return todo
|
||||
else:
|
||||
print_error(f"Failed to create todo. Status code: {response.status_code}")
|
||||
print_error(f"Response: {response.text}")
|
||||
return {}
|
||||
|
||||
def get_todo(todo_id: int) -> Dict[str, Any]:
|
||||
"""Get a specific todo by ID"""
|
||||
print_info(f"Getting todo with ID: {todo_id}")
|
||||
response = requests.get(f"{BASE_URL}/todos/{todo_id}")
|
||||
if response.status_code == 200:
|
||||
todo = response.json()
|
||||
print_success(f"Got todo: {todo['title']}")
|
||||
return todo
|
||||
else:
|
||||
print_error(f"Failed to get todo. Status code: {response.status_code}")
|
||||
print_error(f"Response: {response.text}")
|
||||
return {}
|
||||
|
||||
def get_all_todos() -> list:
|
||||
"""Get all todos"""
|
||||
print_info("Getting all todos")
|
||||
response = requests.get(f"{BASE_URL}/todos/")
|
||||
if response.status_code == 200:
|
||||
todos = response.json()
|
||||
print_success(f"Got {len(todos)} todos")
|
||||
return todos
|
||||
else:
|
||||
print_error(f"Failed to get todos. Status code: {response.status_code}")
|
||||
print_error(f"Response: {response.text}")
|
||||
return []
|
||||
|
||||
def update_todo(todo_id: int, data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Update a specific todo"""
|
||||
print_info(f"Updating todo with ID: {todo_id}")
|
||||
response = requests.put(f"{BASE_URL}/todos/{todo_id}", json=data)
|
||||
if response.status_code == 200:
|
||||
todo = response.json()
|
||||
print_success(f"Updated todo: {todo['title']}")
|
||||
return todo
|
||||
else:
|
||||
print_error(f"Failed to update todo. Status code: {response.status_code}")
|
||||
print_error(f"Response: {response.text}")
|
||||
return {}
|
||||
|
||||
def delete_todo(todo_id: int) -> bool:
|
||||
"""Delete a specific todo"""
|
||||
print_info(f"Deleting todo with ID: {todo_id}")
|
||||
response = requests.delete(f"{BASE_URL}/todos/{todo_id}")
|
||||
if response.status_code == 204:
|
||||
print_success(f"Deleted todo with ID: {todo_id}")
|
||||
return True
|
||||
else:
|
||||
print_error(f"Failed to delete todo. Status code: {response.status_code}")
|
||||
print_error(f"Response: {response.text}")
|
||||
return False
|
||||
|
||||
def run_tests() -> None:
|
||||
"""Run all tests"""
|
||||
print_info("Starting API tests")
|
||||
|
||||
# Test health endpoint
|
||||
if not test_health_endpoint():
|
||||
print_error("Health endpoint test failed. Make sure the server is running.")
|
||||
sys.exit(1)
|
||||
|
||||
# Test creating a todo
|
||||
todo = create_todo("Test Todo", "This is a test todo", False)
|
||||
if not todo:
|
||||
print_error("Failed to create todo. Stopping tests.")
|
||||
sys.exit(1)
|
||||
|
||||
todo_id = todo["id"]
|
||||
|
||||
# Test getting a specific todo
|
||||
get_todo(todo_id)
|
||||
|
||||
# Test getting all todos
|
||||
get_all_todos()
|
||||
|
||||
# Test updating a todo
|
||||
updated_todo = update_todo(todo_id, {"title": "Updated Test Todo", "completed": True})
|
||||
if not updated_todo:
|
||||
print_error("Failed to update todo.")
|
||||
|
||||
# Test deleting a todo
|
||||
if not delete_todo(todo_id):
|
||||
print_error("Failed to delete todo.")
|
||||
|
||||
print_info("All tests completed")
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_tests()
|
Loading…
x
Reference in New Issue
Block a user