fix(api): return created task instead of 500 on POST /tasks
TaskResponse declared created_at and updated_at as str, but both are
timestamp columns and psycopg2 returns datetime objects. Pydantic
rejected every response, so the endpoint raised ResponseValidationError
after the INSERT had already committed.
Every task creation therefore looked like a failure, and the natural
retry failed again with a genuine duplicate-key violation, making it
appear the first attempt had done nothing.
Declaring them as datetime leaves the JSON on the wire unchanged
(FastAPI serialises to ISO 8601) and matches what GET /tasks/{task_name}
already returned.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,14 @@ All notable changes to The Scheduler will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
- `POST /tasks` returned HTTP 500 after successfully creating the task. The response
|
||||
model declared `created_at`/`updated_at` as strings while the database returns
|
||||
timestamps, so every create looked like a failure and retrying hit a duplicate-key
|
||||
error.
|
||||
|
||||
## [1.1.3] - 2026-01-08
|
||||
|
||||
### Changed
|
||||
|
||||
+8
-2
@@ -3,6 +3,7 @@ Pydantic models for The Scheduler API.
|
||||
"""
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional, Dict, Any
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
|
||||
|
||||
@@ -203,8 +204,13 @@ class TaskUpdate(BaseModel):
|
||||
|
||||
class TaskResponse(TaskCreate):
|
||||
"""Response model for task operations."""
|
||||
created_at: str
|
||||
updated_at: Optional[str] = None
|
||||
# These are `timestamp` columns, so psycopg2 hands back datetime objects.
|
||||
# Declaring them as `str` made Pydantic reject every create response, which
|
||||
# 500'd the endpoint *after* the row had already been inserted and committed.
|
||||
# FastAPI serialises datetime to an ISO 8601 string, so the JSON on the wire
|
||||
# is unchanged — and now matches what GET /tasks/{name} already returned.
|
||||
created_at: datetime
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
Reference in New Issue
Block a user