Skip to content

feat(api): implement task CRUD API endpoints#5

Merged
raychrisgdp merged 3 commits intomainfrom
pr-002-task-crud-api
Jan 3, 2026
Merged

feat(api): implement task CRUD API endpoints#5
raychrisgdp merged 3 commits intomainfrom
pr-002-task-crud-api

Conversation

@raychrisgdp
Copy link
Copy Markdown
Owner

@raychrisgdp raychrisgdp commented Jan 2, 2026

Summary

Issues & Goals:

  • Enable task management through REST API endpoints for creating, reading, updating, and deleting tasks
  • Establish stable API contract for future UI development (TUI, web UI)
  • Provide filtering and pagination capabilities for task lists
  • Standardize error responses and input validation at API boundary

Implementation Highlights:

  • Backend API: Implemented FastAPI router with CRUD endpoints (POST /api/v1/tasks, GET /api/v1/tasks, GET /api/v1/tasks/{id}, PATCH /api/v1/tasks/{id}, DELETE /api/v1/tasks/{id}) in backend/api/v1/tasks.py
  • Service Layer: Created task service layer (backend/services/task_service.py) with business logic for task operations, filtering, and pagination
  • Schemas: Added Pydantic schemas (backend/schemas/task.py) for request/response validation with TaskCreate, TaskUpdate, TaskResponse, TaskListResponse, and ErrorResponse
  • List Response Format: List responses include total, page, and page_size fields with default ordering (created_at DESC, id ASC) for stable pagination
  • Error Handling: Standardized error responses with {"error": "...", "code": "TASK_NOT_FOUND"} shape for 404s
  • Task Response Contract: Task responses include attachments: [] placeholder until PR-004 lands (no attachment joins)
  • API Testing: Comprehensive test suite (tests/api/test_tasks.py) covering CRUD operations, validation, filtering, pagination, and error cases (24 tests)
  • Configuration Updates: Simplified .env.example to focus on essential settings, updated docs/DEVELOPER_QUICKSTART.md with API testing instructions, and updated PR spec with implementation details

How to Test

Backend API Testing:

  1. Start the API server:

    # Terminal 1: Start API server
    python -m backend.main
    # Server runs on http://127.0.0.1:8080
  2. Swagger UI Testing:

    • Open http://127.0.0.1:8080/docs in your browser
    • Test each endpoint interactively:
      • POST /api/v1/tasks: Create a new task with required fields (title, status, priority)
      • GET /api/v1/tasks: List all tasks with optional filters (status, priority, due_before, due_after)
      • GET /api/v1/tasks/{id}: Retrieve a specific task by ID
      • PATCH /api/v1/tasks/{id}: Update a task (partial updates supported)
      • DELETE /api/v1/tasks/{id}: Delete a task
  3. API Endpoint Testing with curl:

    # Create a task
    curl -X POST http://127.0.0.1:8080/api/v1/tasks \
      -H "Content-Type: application/json" \
      -d '{
        "title": "Test Task",
        "description": "Test Description",
        "status": "pending",
        "priority": "high",
        "eta": "2026-01-15T10:00:00Z",
        "tags": ["test", "api"],
        "metadata": {"source": "manual"}
      }'
    
    # List tasks (default pagination: limit=50, offset=0)
    curl http://127.0.0.1:8080/api/v1/tasks
    
    # List tasks with filters
    curl "http://127.0.0.1:8080/api/v1/tasks?status=pending&priority=high&limit=10&offset=0"
    
    # Get task by ID (replace {id} with actual task ID from create response)
    curl http://127.0.0.1:8080/api/v1/tasks/{id}
    
    # Update task (partial update)
    curl -X PATCH http://127.0.0.1:8080/api/v1/tasks/{id} \
      -H "Content-Type: application/json" \
      -d '{"status": "in_progress", "priority": "critical"}'
    
    # Delete task
    curl -X DELETE http://127.0.0.1:8080/api/v1/tasks/{id}
  4. Expected API Behavior:

    • POST /api/v1/tasks: Returns 201 Created with full task object including id, created_at, updated_at, and attachments: []
    • GET /api/v1/tasks: Returns 200 OK with {"tasks": [...], "total": <int>, "page": <int>, "page_size": <int>} where page = floor(offset / limit) + 1
    • GET /api/v1/tasks/{id}: Returns 200 OK with task object, or 404 with {"error": "Task not found", "code": "TASK_NOT_FOUND"}
    • PATCH /api/v1/tasks/{id}: Returns 200 OK with updated task object, or 404 with error shape
    • DELETE /api/v1/tasks/{id}: Returns 204 No Content on success, or 404 with error shape
    • List Response: Includes total (total count matching filters), page (calculated from offset/limit), and page_size (limit value)
    • Default Ordering: Tasks ordered by created_at DESC, id ASC for stable pagination
    • Task Response: All task responses include attachments: [] as empty list (placeholder for PR-004)
  5. Validation Testing:

    # Test empty title validation (should return 422)
    curl -X POST http://127.0.0.1:8080/api/v1/tasks \
      -H "Content-Type: application/json" \
      -d '{"title": "", "status": "pending", "priority": "medium"}'
    
    # Test invalid status enum (should return 422)
    curl -X POST http://127.0.0.1:8080/api/v1/tasks \
      -H "Content-Type: application/json" \
      -d '{"title": "Test", "status": "invalid_status", "priority": "medium"}'
    
    # Test invalid priority enum (should return 422)
    curl -X POST http://127.0.0.1:8080/api/v1/tasks \
      -H "Content-Type: application/json" \
      -d '{"title": "Test", "status": "pending", "priority": "invalid_priority"}'
    
    # Test 404 for non-existent task
    curl http://127.0.0.1:8080/api/v1/tasks/00000000-0000-0000-0000-000000000000
  6. Filtering and Pagination Testing:

    # Filter by status
    curl "http://127.0.0.1:8080/api/v1/tasks?status=pending"
    
    # Filter by priority
    curl "http://127.0.0.1:8080/api/v1/tasks?priority=high"
    
    # Filter by due date range
    curl "http://127.0.0.1:8080/api/v1/tasks?due_after=2026-01-01T00:00:00Z&due_before=2026-01-31T23:59:59Z"
    
    # Test pagination (limit=10, offset=0)
    curl "http://127.0.0.1:8080/api/v1/tasks?limit=10&offset=0"
    
    # Test pagination (limit=10, offset=10)
    curl "http://127.0.0.1:8080/api/v1/tasks?limit=10&offset=10"
    
    # Verify response includes total, page, page_size
    # Response should have: {"tasks": [...], "total": <count>, "page": <calculated>, "page_size": 10}
  7. Automated Test Execution:

    # Run all API tests
    uv run pytest tests/api/test_tasks.py -v
    
    # Run specific test categories
    uv run pytest tests/api/test_tasks.py::test_create_task -v
    uv run pytest tests/api/test_tasks.py::test_list_tasks -v
    uv run pytest tests/api/test_tasks.py::test_list_tasks_with_filters -v
    uv run pytest tests/api/test_tasks.py::test_list_tasks_pagination -v

Expected Behavior:

  • All CRUD endpoints return appropriate status codes (201, 200, 204, 404, 422)
  • List responses include total, page, and page_size fields
  • Tasks are ordered by created_at DESC, id ASC by default
  • Task responses include attachments: [] as empty list
  • Error responses use standard shape: {"error": "...", "code": "TASK_NOT_FOUND"}
  • Validation errors return 422 with field-level error details
  • Filters (status, priority, due_before, due_after) work correctly
  • Pagination defaults to limit=50, offset=0 and enforces limits

Related Issues

  • None

Author Checklist

  • Synced with latest main branch
  • Self-reviewed
  • All tests pass locally
  • Documentation updated (if applicable)
  • No breaking changes (or documented if intentional)

Additional Notes

Key Implementation Areas for Review

Backend API:

  • backend/api/v1/tasks.py: FastAPI router with 5 CRUD endpoints - verify error handling, response models, and query parameter validation
  • backend/main.py: Router registration at /api/v1 prefix - verify FastAPI app configuration

Service Layer:

  • backend/services/task_service.py: Business logic for task operations - verify filtering logic, pagination calculation (page = floor(offset / limit) + 1), and default ordering (created_at DESC, id ASC)
  • backend/services/__init__.py: Service exports - verify public API exports match usage

Schemas:

  • backend/schemas/task.py: Pydantic schemas for validation - verify TaskCreate, TaskUpdate, TaskResponse, TaskListResponse, and ErrorResponse match API contract
  • Verify TaskResponse includes attachments: [] as empty list (placeholder for PR-004)
  • Verify TaskListResponse includes total, page, and page_size fields

Testing:

  • tests/api/test_tasks.py: Comprehensive API test suite (24 tests) - verify CRUD operations, validation, filtering, pagination, and error cases are covered
  • Verify test isolation (each test uses isolated database via tmp_path fixture)

Configuration & Documentation:

  • .env.example: Simplified configuration - verify only essential settings are included
  • docs/02-implementation/pr-specs/PR-002-task-crud-api.md: Spec updates - verify implementation matches spec requirements
  • docs/DEVELOPER_QUICKSTART.md: Dev setup instructions - verify API testing commands are accurate
  • pyproject.toml: Dependency updates - verify typer dependency change (removed [all] extra)

Testing Notes

  • Worktree state: Implementation files are staged but not yet committed - PR description reflects full scope including staged changes
  • API contract compliance: All endpoints match PR-002 spec requirements including list response shape (total, page, page_size) and default ordering
  • Error handling: Standardized error responses use {"error": "...", "code": "TASK_NOT_FOUND"} shape for 404s
  • Task response contract: All task responses include attachments: [] as empty list (placeholder until PR-004)
  • Pagination calculation: page = floor(offset / limit) + 1 when limit > 0, otherwise page = 1
  • Default ordering: Tasks ordered by created_at DESC, id ASC for stable pagination across requests
  • Test coverage: 24 tests covering CRUD operations, validation, filtering, pagination, and error cases (per test results document)
  • Manual verification: Use Swagger UI (/docs) or curl commands to test endpoints interactively
  • Database isolation: Tests use tmp_path fixture for isolated database per test

- Set DEBUG to false in .env.example for production readiness.
- Removed unnecessary database and LLM configuration options from .env.example.
- Updated the Typer dependency in pyproject.toml and uv.lock to remove the 'all' extra, simplifying the installation process.
- Improved developer quickstart instructions for installing dependencies and running the application.
- Enhanced PR-002 task CRUD API documentation with additional details on response shapes and pagination.

These changes aim to streamline configuration, clarify setup instructions, and improve API documentation.
@raychrisgdp raychrisgdp self-assigned this Jan 2, 2026
@raychrisgdp raychrisgdp changed the title chore: update environment configuration and dependencies feat(api): implement task CRUD API endpoints Jan 2, 2026
@raychrisgdp raychrisgdp marked this pull request as draft January 2, 2026 18:51
- Added a new API v1 for task management, including endpoints for creating, retrieving, updating, and deleting tasks.
- Introduced task schemas for request validation and response formatting.
- Implemented error handling for task not found scenarios with a standardized error response.
- Updated the Makefile to include precommit checks in the test coverage command.
- Removed linting step from CI workflow to streamline the testing process.

These changes enhance the API functionality for task management and improve error handling, contributing to a more robust application.
- Add model_validator to TaskUpdate to reject title: null (prevents DB integrity errors)
- Fix async generator return type annotation in test fixture
- Add noqa comment for magic number in pagination test
- Add test for null title rejection

Fixes CI/CD issues: mypy errors and ruff warnings
@raychrisgdp raychrisgdp marked this pull request as ready for review January 3, 2026 04:25
@raychrisgdp raychrisgdp merged commit 081f3a0 into main Jan 3, 2026
2 checks passed
@raychrisgdp raychrisgdp deleted the pr-002-task-crud-api branch January 3, 2026 04:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant