diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 8d016b2..15ab749 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -7,7 +7,7 @@ REST API for managing football players built with Rust and Rocket. Implements CR ## Tech Stack - **Language**: Rust 2024 Edition (enforced via `rust-toolchain.toml`) -- **Framework**: Rocket 0.5 (async) +- **Framework**: Rocket 0.5.1 (async) - **Serialization**: Serde (JSON) - **Unique IDs**: uuid (v4 + serde features) - **ORM / Migrations**: Diesel (SQLite + r2d2 features) + diesel_migrations; `embed_migrations!()` runs pending migrations on startup diff --git a/README.md b/README.md index 8833d63..b32bd65 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,7 @@ Once the application is running, you can access: - **API Server**: `http://localhost:9000` - **Health Check**: `http://localhost:9000/health` +- **Swagger UI**: `http://localhost:9000/swagger-ui/` ## Containers @@ -197,8 +198,10 @@ docker pull ghcr.io/nanotaboada/rust-samples-rocket-restful:latest ## Environment Variables ```bash -# Database storage path (default: ./storage/players-sqlite3.db) -STORAGE_PATH=./storage/players-sqlite3.db +# Database storage path +# Container default (set in Dockerfile): /storage/players-sqlite3.db +# Local dev fallback (no env var set): storage/players-sqlite3.db +STORAGE_PATH=/storage/players-sqlite3.db # Rocket profile: debug or release (default: debug) ROCKET_PROFILE=release diff --git a/rest/players.rest b/rest/players.rest index 80dd0f7..52dc73d 100644 --- a/rest/players.rest +++ b/rest/players.rest @@ -3,9 +3,14 @@ ### - VS Code: REST Client extension (humao.rest-client) ### - JetBrains IDEs: built-in HTTP Client -@baseUrl = http://localhost:9000 -@newSquadNumber = 27 -@existingSquadNumber = 23 +@baseUrl = http://localhost:9000 +@existingId = acc433bf-d505-51fe-831e-45eb44c4d43c +@nonexistentId = 00000000-0000-0000-0000-000000000000 +@unknownId = f47ac10b-58cc-4372-a567-0e02b2c3d479 +@createdSquadNumber = 27 +@existingSquadNumber = 23 +@nonexistentSquadNumber = 999 +@unknownSquadNumber = 28 # ----------------------------------------------------------------------------- @@ -15,7 +20,9 @@ GET {{baseUrl}}/health ### -### Create Player +# POST /players --------------------------------------------------------------- + +### Create Player (valid body) # POST /players → 201 Created POST {{baseUrl}}/players Content-Type: application/json @@ -25,7 +32,28 @@ Content-Type: application/json "middleName": "", "lastName": "Lo Celso", "dateOfBirth": "1996-07-09T00:00:00.000Z", - "squadNumber": 27, + "squadNumber": {{createdSquadNumber}}, + "position": "Central Midfield", + "abbrPosition": "CM", + "team": "Real Betis Balompié", + "league": "La Liga", + "starting11": false +} + +### + +### Create Player (duplicate squad number) +# POST /players → 409 Conflict +# Requires: "Create Player (valid body)" above to have run first. +POST {{baseUrl}}/players +Content-Type: application/json + +{ + "firstName": "Giovani", + "middleName": "", + "lastName": "Lo Celso", + "dateOfBirth": "1996-07-09T00:00:00.000Z", + "squadNumber": {{createdSquadNumber}}, "position": "Central Midfield", "abbrPosition": "CM", "team": "Real Betis Balompié", @@ -35,26 +63,52 @@ Content-Type: application/json ### +# GET /players ---------------------------------------------------------------- + ### Get All Players # GET /players → 200 OK GET {{baseUrl}}/players ### -### Get Player by ID -# GET /players/:id → 200 OK -GET {{baseUrl}}/players/acc433bf-d505-51fe-831e-45eb44c4d43c +# GET /players/{id} ----------------------------------------------------------- + +### Get Player by ID (existing) +# GET /players/{id} → 200 OK +GET {{baseUrl}}/players/{{existingId}} + +### + +### Get Player by ID (nonexistent) +# GET /players/{id} → 404 Not Found +GET {{baseUrl}}/players/{{nonexistentId}} ### -### Get Player by Squad Number -# GET /players/squadnumber/:squadnumber → 200 OK +### Get Player by ID (unknown) +# GET /players/{id} → 404 Not Found +GET {{baseUrl}}/players/{{unknownId}} + +### + +# GET /players/squadnumber/{squad_number} ------------------------------------- + +### Get Player by Squad Number (existing) +# GET /players/squadnumber/{squad_number} → 200 OK GET {{baseUrl}}/players/squadnumber/10 ### -### Update Player -# PUT /players/squadnumber/:squadnumber → 200 OK +### Get Player by Squad Number (nonexistent) +# GET /players/squadnumber/{squad_number} → 404 Not Found +GET {{baseUrl}}/players/squadnumber/{{nonexistentSquadNumber}} + +### + +# PUT /players/squadnumber/{squad_number} ------------------------------------- + +### Update Player (existing) +# PUT /players/squadnumber/{squad_number} → 204 No Content PUT {{baseUrl}}/players/squadnumber/{{existingSquadNumber}} Content-Type: application/json @@ -63,7 +117,27 @@ Content-Type: application/json "middleName": "", "lastName": "Martínez", "dateOfBirth": "1992-09-02T00:00:00.000Z", - "squadNumber": 23, + "squadNumber": {{existingSquadNumber}}, + "position": "Goalkeeper", + "abbrPosition": "GK", + "team": "Aston Villa FC", + "league": "Premier League", + "starting11": true +} + +### + +### Update Player (nonexistent) +# PUT /players/squadnumber/{squad_number} → 404 Not Found +PUT {{baseUrl}}/players/squadnumber/{{nonexistentSquadNumber}} +Content-Type: application/json + +{ + "firstName": "Emiliano", + "middleName": "", + "lastName": "Martínez", + "dateOfBirth": "1992-09-02T00:00:00.000Z", + "squadNumber": {{existingSquadNumber}}, "position": "Goalkeeper", "abbrPosition": "GK", "team": "Aston Villa FC", @@ -73,9 +147,43 @@ Content-Type: application/json ### -### Delete Player -# DELETE /players/squadnumber/:squadnumber → 204 No Content -# Requires Create Player to have been run first. -DELETE {{baseUrl}}/players/squadnumber/{{newSquadNumber}} +### Update Player (unknown) +# PUT /players/squadnumber/{squad_number} → 404 Not Found +PUT {{baseUrl}}/players/squadnumber/{{unknownSquadNumber}} +Content-Type: application/json + +{ + "firstName": "Emiliano", + "middleName": "", + "lastName": "Martínez", + "dateOfBirth": "1992-09-02T00:00:00.000Z", + "squadNumber": {{existingSquadNumber}}, + "position": "Goalkeeper", + "abbrPosition": "GK", + "team": "Aston Villa FC", + "league": "Premier League", + "starting11": true +} + +### + +# DELETE /players/squadnumber/{squad_number} ---------------------------------- + +### Delete Player (existing) +# DELETE /players/squadnumber/{squad_number} → 204 No Content +# Requires: "Create Player (valid body)" above to have run first. +DELETE {{baseUrl}}/players/squadnumber/{{createdSquadNumber}} + +### + +### Delete Player (nonexistent) +# DELETE /players/squadnumber/{squad_number} → 404 Not Found +DELETE {{baseUrl}}/players/squadnumber/{{nonexistentSquadNumber}} + +### + +### Delete Player (unknown) +# DELETE /players/squadnumber/{squad_number} → 404 Not Found +DELETE {{baseUrl}}/players/squadnumber/{{unknownSquadNumber}} ### diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index 573c577..bb390d8 100644 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -7,17 +7,17 @@ log() { return 0 } -VOLUME_STORAGE_PATH="${STORAGE_PATH:-/storage/players-sqlite3.db}" - log "✔ Starting container..." -mkdir -p "$(dirname "$VOLUME_STORAGE_PATH")" +STORAGE_PATH="${STORAGE_PATH:-storage/players-sqlite3.db}" + +mkdir -p "$(dirname "$STORAGE_PATH")" -if [ ! -f "$VOLUME_STORAGE_PATH" ]; then +if [ ! -f "$STORAGE_PATH" ]; then log "⚠️ No existing database file found in volume." log "🗄️ Diesel migrations will initialize the database on first start." else - log "✔ Existing database file found at $VOLUME_STORAGE_PATH." + log "✔ Existing database file found at $STORAGE_PATH." fi log "✔ Ready!"