コンテンツにスキップ

レース 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

POST /v1/races

リクエストボディ

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

処理フロー

  1. リクエストを受信する
  2. アップロードされた JSON ファイルをパースし、race_id を取り出す
  3. race_id で3つのレースコレクションを横断検索し、既存レースが無いことを確認する
  4. type に対応するコレクションへレースを保存する
  5. 保存したレースを返す
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

PUT /v1/races/prediction

リクエストボディ

フィールド データ型 必須 備考
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

GET /v1/races

クエリパラメータ

パラメータ データ型 必須 備考
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

GET /v1/races/{race_id}
パスパラメータ データ型 備考
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

PUT /v1/races/{race_id}

リクエストボディ

{
  "name": "string",
  "race_result": {}
}
フィールド データ型 必須 備考
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

DELETE /v1/races/{race_id}

レスポンス

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]