レース API
オートレース・競輪・競馬のレース情報を管理するエンドポイントです。
このデータは AI 記事生成(article)・AI ブログ生成(blog)の入力となり、article.race_id / blog.race_id から参照されます。
競技種別(RacingType)
レースは競技種別ごとに auto_racing / bicycle_racing / horse_racing の3コレクションへ保存されます。
レースドキュメント自体は種別を持たず、コレクションが種別を表現します。
| 値 | 競技 |
|---|---|
auto_racing |
オートレース |
bicycle_racing |
競輪 |
horse_racing |
競馬 |
race_id(= _id)は競技をまたいで一意のため、詳細取得・更新・削除では種別の指定が不要です。
API が3コレクションを横断検索して該当レースを特定します。
一覧取得(GET /v1/races)だけは、どのコレクションを引くかを決めるため type が必須です。
レーススキーマ
| フィールド | データ型 | 備考 |
|---|---|---|
| id | string | _id。レース結果 JSON 内の race_id |
| type | enum | auto_racing / bicycle_racing / horse_racing |
| name | string | アップロードされたレース結果 JSON のファイル名(.json を除いた部分) |
| race_result | object | レース結果 JSON の中身 |
| prediction | object | null | レース前の出走表と AI予想印。未登録のレースでは null |
| article_status | enum | null | レースに紐づく最新記事のステータス。記事が無い場合は null(一覧取得でのみ設定される) |
| created_at | number | UNIXタイムスタンプ(ミリ秒) |
| updated_at | number | UNIXタイムスタンプ(ミリ秒) |
POST /v1/races
概要
レース結果を新規登録します。
リクエストボディに JSON ペイロードは指定せず、競技種別(type)とレース結果の JSON ファイルを
multipart/form-data でアップロードします。アップロードした JSON ファイルの中身がそのまま
race_result として登録されます。
リクエストとレスポンス
ヘッダー
リクエストヘッダー
Content-Type: multipart/form-data
レスポンスヘッダー
Content-Type: application/json
URI
リクエストボディ
multipart/form-data 形式で以下のフィールドを指定します。
| フィールド | データ型 | 必須 | 備考 |
|---|---|---|---|
| type | enum | ◯ | auto_racing / bicycle_racing / horse_racing |
| file | binary | ◯ | レース結果の JSON ファイル |
サーバー側では以下のように各フィールドを決定して格納します。
_id: JSON 内のrace_idの値name: アップロードされたファイル名から.jsonを除いた部分(例:20260504_飯塚_05R.json→20260504_飯塚_05R)race_result: JSON ファイルの中身全体をそのまま格納
参考: レース結果 JSON の中身の例(フォーマットはスクレイピング結果に準ずる)
{
"race_id": "string",
"race_date": "string",
"track_name": "string",
"race_number": "string",
"race_name": "string",
"weather": "string",
"entries": []
}
レスポンス
201 Created
{
"id": "string",
"type": "horse_racing",
"name": "string",
"race_result": {},
"prediction": null,
"article_status": null,
"created_at": 1234567890000,
"updated_at": 1234567890000
}
例外処理
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| ファイルが指定されていない | 400 | Bad Request |
| JSON としてパースできない | 400 | Bad Request |
JSON に race_id フィールドが含まれていない |
400 | Bad Request |
type が不正 |
422 | Unprocessable Entity |
同じ race_id のレースが既に存在する |
409 | Conflict |
| 内部サーバーエラー | 500 | Internal Server Error |
処理フロー
- リクエストを受信する
- アップロードされた JSON ファイルをパースし、
race_idを取り出す race_idで3つのレースコレクションを横断検索し、既存レースが無いことを確認するtypeに対応するコレクションへレースを保存する- 保存したレースを返す
flowchart TD
Start([POST /v1/races]) --> Parse[JSON ファイルをパース]
Parse -->|不正| E400[400 Bad Request]
Parse -->|race_id なし| E400
Parse -->|OK| Exists[race_id で3コレクションを横断検索]
Exists -->|既に存在| E409[409 Conflict]
Exists -->|存在しない| Save[type に対応するコレクションへ保存]
Save --> Success[201 Created]
PUT /v1/races/prediction
概要
既存のレースへ AI予想(レース前の出走表と予想印)を紐づけます。
予想はレース結果より後から取得することがあるため、レース登録とは別の操作にしています。
登録した prediction は予想ブログの生成(POST /v1/blogs/generate の kind=prediction)の入力になります。
リクエストとレスポンス
ヘッダー
リクエストヘッダー
Content-Type: multipart/form-data
レスポンスヘッダー
Content-Type: application/json
URI
リクエストボディ
| フィールド | データ型 | 必須 | 備考 |
|---|---|---|---|
| file | binary | ◯ | AI予想の JSON ファイル。race_id と entries を含む必要がある |
対象レースは JSON 内の race_id で特定するため、パス・フォームでの指定は不要です。
レスポンス
200 OK
レーススキーマ(prediction が設定された状態)を返します。
例外処理
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| ファイルが指定されていない | 400 | Bad Request |
| JSON としてパースできない | 400 | Bad Request |
JSON に race_id フィールドが含まれていない |
400 | Bad Request |
JSON に entries フィールドが含まれていない |
400 | Bad Request |
| レースが存在しない | 404 | Not Found |
| 内部サーバーエラー | 500 | Internal Server Error |
処理フロー
flowchart TD
Start([PUT /v1/races/prediction]) --> Parse[JSON ファイルをパース]
Parse -->|不正| E400[400 Bad Request]
Parse -->|OK| Find[race_id で3コレクションを横断検索]
Find -->|存在しない| E404[404 Not Found]
Find -->|存在する| Save[prediction を保存]
Save --> Success[200 OK]
ルーティング順序
/races/prediction は /races/{race_id} より先に宣言されています。
後に宣言すると prediction が race_id として解釈されてしまうためです。
GET /v1/races
概要
指定した競技種別のレース一覧を取得します。
一覧では、レースごとに紐づく最新記事のステータス(article_status)も返します。
管理画面の一覧でステータスバッジを表示するためのもので、レースごとに個別取得すると N+1 になるため
一括で解決しています。
リクエストとレスポンス
URI
クエリパラメータ
| パラメータ | データ型 | 必須 | 備考 |
|---|---|---|---|
| type | enum | ◯ | auto_racing / bicycle_racing / horse_racing |
| page | number | 取得するページ番号。デフォルト: 1 |
|
| size | number | 1ページあたりの件数。デフォルト: 10 |
|
| order | enum | asc / desc(name 基準)。デフォルト: desc |
並び順は name 基準
他のリソースと異なり、レース一覧は name(例: 20260504_飯塚_05R)でソートします。
日付始まりのため、辞書順がそのままレース日順になります。
レスポンス
200 OK
{
"list": [
{
"id": "string",
"type": "horse_racing",
"name": "string",
"race_result": {},
"prediction": null,
"article_status": "draft",
"created_at": 1234567890000,
"updated_at": 1234567890000
}
],
"current_page": 1,
"total_count": 10
}
例外処理
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
type が未指定または不正 |
422 | Unprocessable Entity |
| 内部サーバーエラー | 500 | Internal Server Error |
GET /v1/races/{race_id}
概要
指定したレースを取得します。race_id は競技をまたいで一意のため、種別の指定は不要です。
リクエストとレスポンス
URI
| パスパラメータ | データ型 | 備考 |
|---|---|---|
| race_id | string | レースの _id |
レスポンス
200 OK
レーススキーマを返します(article_status は null)。
例外処理
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| レースが存在しない | 404 | Not Found |
| 内部サーバーエラー | 500 | Internal Server Error |
PUT /v1/races/{race_id}
概要
指定したレースを更新します。
リクエストとレスポンス
ヘッダー
リクエストヘッダー
Content-Type: application/json
URI
リクエストボディ
| フィールド | データ型 | 必須 | 備考 |
|---|---|---|---|
| name | string | レース名 | |
| race_result | object | レース結果 JSON の中身 |
指定されなかった(null の)フィールドは更新しません。
prediction は本エンドポイントでは更新できません(PUT /v1/races/prediction を使用してください)。
レスポンス
200 OK
更新後のレーススキーマを返します。
例外処理
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| リクエストボディが不正 | 422 | Unprocessable Entity |
| レースが存在しない | 404 | Not Found |
| 内部サーバーエラー | 500 | Internal Server Error |
DELETE /v1/races/{race_id}
概要
指定したレースを論理削除します。
リクエストとレスポンス
URI
レスポンス
204 No Content
例外処理
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| レースが存在しない | 404 | Not Found |
| 内部サーバーエラー | 500 | Internal Server Error |
処理フロー
flowchart TD
Start([DELETE /v1/races/race_id]) --> Find[race_id で3コレクションを横断検索]
Find -->|存在しない| E404[404 Not Found]
Find -->|存在する| Delete[deleted_at を設定]
Delete --> Success[204 No Content]