Past Blog API
Endpoints for managing past blog articles (old_blog) targeted for migration. Registered past blogs
are the input for AI rewriting (blog_rewriter); the results are stored in blog.
Past blog schema
| Field | Type | Notes |
|---|---|---|
| id | string | _id |
| race_id | string | null | _id of the linked race; not every past blog has one |
| race_type | enum | null | auto_racing / bicycle_racing / horse_racing |
| blog_type | string | null | Series type (e.g. jockey interview, Saito column) |
| category | string | null | Broad category (e.g. interview, race recap, prediction). Stored as a string |
| source_url | string | null | URL of the source blog article |
| published_at | number | null | Publish time of the source article. UNIX timestamp (ms) |
| name | string | Title |
| body_html | string | HTML body from the source |
| created_at | number | UNIX timestamp (ms) |
| updated_at | number | UNIX timestamp (ms) |
embedding is not returned
The embedding vector is kept internally and never included in API responses.
POST /v1/old_blogs
Overview
Registers a past blog article.
On registration, "category + title + body (tags stripped)" is flattened to text and embedded with
Amazon Bedrock Titan Text Embeddings v2. That vector is carried over to blog on rewrite and used
for related-blog search.
Embedding is supplementary: if it fails, registration still succeeds (embedding stays unset).
Request and Response
Headers
Request
Content-Type: application/json
Response
Content-Type: application/json
URI
Request body
{
"name": "string",
"body_html": "string",
"race_id": "string",
"race_type": "horse_racing",
"blog_type": "string",
"category": "string",
"source_url": "string",
"published_at": 1234567890000
}
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | โฏ | Title |
| body_html | string | โฏ | HTML body |
| race_id | string | _id of the linked race |
|
| race_type | enum | auto_racing / bicycle_racing / horse_racing |
|
| blog_type | string | Series type | |
| category | string | Broad category; used by blog_builder to pick the article template | |
| source_url | string | Source URL; also the base for absolutizing relative image src values |
|
| published_at | number | Source publish time. UNIX timestamp (ms) |
Response
201 Created โ returns the past blog schema.
Error handling
| Description | Status code | Status |
|---|---|---|
| Invalid request body | 422 | Unprocessable Entity |
| Internal server error | 500 | Internal Server Error |
Processing flow
flowchart TD
Start([POST /v1/old_blogs]) --> Embed[Embed category + title + body]
Embed -->|failure| Save[Store without a vector]
Embed -->|success| Save2[Store with the vector]
Save --> Success[201 Created]
Save2 --> Success
GET /v1/old_blogs
Overview
Lists past blog articles.
URI
Query parameters
| Parameter | Type | Required | Notes |
|---|---|---|---|
| race_id | string | Filter by race | |
| page | number | Page number. Default: 1 |
|
| size | number | Items per page. Default: 10 |
|
| order | enum | asc / desc (by updated_at). Default: desc |
Response
200 OK
{
"list": [
{
"id": "string",
"race_id": "string",
"race_type": "horse_racing",
"blog_type": null,
"category": "ใฌใผในๅ้กง",
"source_url": "string",
"published_at": 1234567890000,
"name": "string",
"body_html": "string",
"created_at": 1234567890000,
"updated_at": 1234567890000
}
],
"current_page": 1,
"total_count": 10
}
GET /v1/old_blogs/{old_blog_id}
Overview
Fetches a single past blog article.
Response
200 OK โ returns the past blog schema.
Error handling
| Description | Status code | Status |
|---|---|---|
| Past blog not found | 404 | Not Found |
| Internal server error | 500 | Internal Server Error |
PUT /v1/old_blogs/{old_blog_id}
Overview
Updates only the category of a past blog article.
Because the embedding is generated with the category included, changing the category regenerates the vector. If regeneration fails, the existing vector is kept and the update proceeds.
If the category is unchanged, nothing is written and the current record is returned.
URI
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
| category | string | Broad category |
Response
200 OK โ returns the updated past blog schema.
Error handling
| Description | Status code | Status |
|---|---|---|
| Past blog not found | 404 | Not Found |
| Internal server error | 500 | Internal Server Error |
No DELETE
There is no delete endpoint for past blogs.
POST /v1/old_blogs/{old_blog_id}/rewrite
Overview
Starts a rewrite of the given past blog.
A blog is created in generating state and a job is dispatched to the blog_rewriter Lambda over
SQS (the blog-rewriter queue). The new blog inherits:
| Field | Source |
|---|---|
name |
old_blog.name |
race_id |
old_blog.race_id, falling back to the request's race_id |
race_type |
old_blog.race_type, otherwise resolved by looking up the race |
blog_type |
old_blog.blog_type |
source_url |
old_blog.source_url |
category_id |
A category record whose name matches old_blog.category; no category if none matches |
embedding |
old_blog.embedding |
When the blog is not tied to a race, race video / race result analysis is skipped and only a content-preserving rewrite is performed.
URI
| Path parameter | Type | Notes |
|---|---|---|
| old_blog_id | string | old_blog._id |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
| race_id | string | Race _id to use when old_blog.race_id is unset. The body itself may be omitted |
Response
202 Accepted
| Field | Type | Notes |
|---|---|---|
| id | string | _id of the created blog |
Error handling
| Description | Status code | Status |
|---|---|---|
| Past blog not found | 404 | Not Found |
race_id given but the race does not exist |
404 | Not Found |
| Internal server error | 500 | Internal Server Error |
Processing flow
flowchart TD
Start([POST /v1/old_blogs/old_blog_id/rewrite]) --> Fetch[Fetch the past blog]
Fetch -->|not found| E404[404 Not Found]
Fetch -->|found| Race[Resolve race linkage]
Race --> Category[Resolve category_id from the category name]
Category --> Save[Save blog as generating]
Save --> SendSQS[Send to blog-rewriter queue]
SendSQS --> Success[202 Accepted]
SendSQS -.->|async| Rewrite[blog_rewriter rewrites the body]
Rewrite -.-> Build[blog_builder builds and stores the HTML]
Build -.-> Draft[status becomes draft]