diff --git a/.vscode/extensions.json b/.vscode/extensions.json index b829afa..dba7a80 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -30,6 +30,9 @@ "ms-azuretools.vscode-containers", // Container Tools - Docker and container management "yy0931.vscode-sqlite3-editor", // SQLite3 Editor - View and edit SQLite databases + // API Development + "humao.rest-client", // REST Client - Send HTTP requests from .http files + // UI Enhancements "github.github-vscode-theme", // GitHub Theme - GitHub color themes "pkief.material-icon-theme", // Material Icon Theme - Material Design file icons diff --git a/.vscode/settings.json b/.vscode/settings.json index 628f754..27d45af 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -34,7 +34,7 @@ "**/.vscode/**", "**/assets/**", "**/htmlcov/**", - "**/postman_collections/**", + "**/rest/**", "**/scripts/**", "**/tools/**", "**/storage/**", diff --git a/CHANGELOG.md b/CHANGELOG.md index 69ebeb0..b8f8d21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,8 @@ This project uses famous football coaches as release codenames, following an A-Z ### Added +- `rest/players.rest` file covering all CRUD operations, compatible with the VS Code REST Client extension (#493) +- `humao.rest-client` added to `.vscode/extensions.json` recommendations (#493) - UUID v4 primary key for the `players` table, replacing the previous integer PK (#66) - `PlayerRequestModel` Pydantic model for POST/PUT request bodies (no `id` field) (#66) - `PlayerResponseModel` Pydantic model for GET/POST response bodies (includes `id: UUID`) (#66) @@ -69,6 +71,8 @@ This project uses famous football coaches as release codenames, following an A-Z ### Removed +- `postman_collections/` directory replaced by `rest/players.rest` (#493) + ### Fixed - POST/PUT/DELETE routes now raise `HTTP 500` on DB failure instead of silently returning success (#66) diff --git a/README.md b/README.md index 12a27bb..ea63d2a 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,10 @@ http://localhost:9000/docs ![API Documentation](assets/images/swagger.png) +## HTTP Requests + +The [`rest/players.rest`](rest/players.rest) file covers all CRUD operations and can be run directly in VS Code with the [REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) extension. + ## Container ### Docker Compose diff --git a/codecov.yml b/codecov.yml index 59796bb..aa0351c 100644 --- a/codecov.yml +++ b/codecov.yml @@ -2,7 +2,7 @@ # https://docs.codecov.com/docs/codecov-yaml coverage: -# https://docs.codecov.com/docs/commit-status + # https://docs.codecov.com/docs/commit-status status: project: default: @@ -42,7 +42,7 @@ ignore: - "^assets/.*" - "^databases/.*" - "^models/.*" - - "^postman_collections/.*" + - "^rest/.*" - "^schemas/.*" - "^tools/.*" - "^tests/.*" diff --git a/postman_collections/python-samples-fastapi-restful.postman_collection.json b/postman_collections/python-samples-fastapi-restful.postman_collection.json deleted file mode 100644 index 40e6ca2..0000000 --- a/postman_collections/python-samples-fastapi-restful.postman_collection.json +++ /dev/null @@ -1,161 +0,0 @@ -{ - "info": { - "_postman_id": "a6f69e7a-9b1f-45d9-a7a6-56f3e824d372", - "name": "python-samples-fastapi-restful", - "description": "🧪 Proof of Concept for a RESTful API made with Python 3 and FastAPI\n\n[https://github.com/nanotaboada/python-samples-fastapi-restful](https://github.com/nanotaboada/python-samples-fastapi-restful)", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "32077259" - }, - "item": [ - { - "name": "Create", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"id\": 12,\n \"firstName\": \"Leandro\",\n \"middleName\": \"Daniel\",\n \"lastName\": \"Paredes\",\n \"dateOfBirth\": \"1994-06-29T00:00:00.000Z\",\n \"squadNumber\": 5,\n \"position\": \"Defensive Midfield\",\n \"abbrPosition\": \"DM\",\n \"team\": \"AS Roma\",\n \"league\": \"Serie A\",\n \"starting11\": false\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:9000/players/", - "protocol": "http", - "host": ["localhost"], - "port": "9000", - "path": ["players"] - }, - "description": "Creates a new Player" - }, - "response": [] - }, - { - "name": "Retrieve", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:9000/players/", - "protocol": "http", - "host": ["localhost"], - "port": "9000", - "path": ["players"] - }, - "description": "Retrieves all the Players" - }, - "response": [] - }, - { - "name": "Retrieve By Id", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:9000/players/1", - "protocol": "http", - "host": ["localhost"], - "port": "9000", - "path": ["players", "1"] - }, - "description": "Retrieves one Player by Id" - }, - "response": [] - }, - { - "name": "Retrieve By Squad Number", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:9000/players/squadnumber/10", - "protocol": "http", - "host": ["localhost"], - "port": "9000", - "path": ["players", "squadnumber", "10"] - }, - "description": "Retrieves one Player by Squad Number" - }, - "response": [] - }, - { - "name": "Update", - "request": { - "method": "PUT", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"id\": 12,\n \"firstName\": \"Leandro\",\n \"middleName\": \"Daniel\",\n \"lastName\": \"Paredes\",\n \"dateOfBirth\": \"1994-06-29T00:00:00.000Z\",\n \"squadNumber\": 5,\n \"position\": \"Defensive Midfield\",\n \"abbrPosition\": \"DM\",\n \"team\": \"AS Roma\",\n \"league\": \"Serie A\",\n \"starting11\": true\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:9000/players/12", - "protocol": "http", - "host": ["localhost"], - "port": "9000", - "path": ["players", "12"] - }, - "description": "Updates an existing Player" - }, - "response": [] - }, - { - "name": "Delete", - "request": { - "method": "DELETE", - "header": [], - "url": { - "raw": "http://localhost:9000/players/12", - "protocol": "http", - "host": ["localhost"], - "port": "9000", - "path": ["players", "12"] - }, - "description": "Deletes an existing Player" - }, - "response": [] - } - ] -} diff --git a/pyproject.toml b/pyproject.toml index d6123da..54a190c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ exclude = ''' | \.vscode | assets | htmlcov - | postman_collections + | rest | scripts | tools | storage diff --git a/rest/players.rest b/rest/players.rest new file mode 100644 index 0000000..2bfa0ac --- /dev/null +++ b/rest/players.rest @@ -0,0 +1,104 @@ +### RESTful API with Python 3 and FastAPI +### https://github.com/nanotaboada/python-samples-fastapi-restful +### +### Requires the REST Client extension for VS Code: +### https://marketplace.visualstudio.com/items?itemName=humao.rest-client +### +### Key design note: +### squad_number = natural key (domain-meaningful, preferred for lookups) +### id (UUID) = surrogate key (internal, opaque, used for CRUD operations) + +@baseUrl = http://localhost:9000 + +# ------------------------------------------------------------------------------ +# Health +# ------------------------------------------------------------------------------ + +### GET /health/ — liveness check +GET {{baseUrl}}/health/ +Accept: application/json + +# ------------------------------------------------------------------------------ +# POST /players/ — Create +# Thiago Almada (squad 16): not seeded in the database, used as the creation +# fixture. No id in the body; the server generates a UUID v4 on creation. +# ------------------------------------------------------------------------------ + +### POST /players/ — Create a new Player +POST {{baseUrl}}/players/ +Content-Type: application/json + +{ + "firstName": "Thiago", + "middleName": "Ezequiel", + "lastName": "Almada", + "dateOfBirth": "2001-04-26T00:00:00.000Z", + "squadNumber": 16, + "position": "Attacking Midfield", + "abbrPosition": "AM", + "team": "Atlanta United FC", + "league": "Major League Soccer", + "starting11": false +} + +# ------------------------------------------------------------------------------ +# GET /players/ — Retrieve all +# ------------------------------------------------------------------------------ + +### GET /players/ — Retrieve all Players +GET {{baseUrl}}/players/ +Accept: application/json + +# ------------------------------------------------------------------------------ +# GET /players/{player_id} — Retrieve by UUID (surrogate key, internal) +# Emiliano Martínez (squad 23): UUID v5, seeded by seed_001. +# ------------------------------------------------------------------------------ + +### GET /players/{player_id} — Retrieve a Player by UUID +GET {{baseUrl}}/players/b04965e6-a9bb-591f-8f8a-1adcb2c8dc39 +Accept: application/json + +# ------------------------------------------------------------------------------ +# GET /players/squadnumber/{squad_number} — Retrieve by Squad Number (natural key, domain) +# Preferred lookup for external consumers. +# ------------------------------------------------------------------------------ + +### GET /players/squadnumber/{squad_number} — Retrieve a Player by Squad Number +GET {{baseUrl}}/players/squadnumber/10 +Accept: application/json + +# ------------------------------------------------------------------------------ +# PUT /players/{player_id} — Update +# Emiliano Martínez (squad 23): UUID v5, seeded by seed_001. +# ------------------------------------------------------------------------------ + +### PUT /players/{player_id} — Update an existing Player +PUT {{baseUrl}}/players/b04965e6-a9bb-591f-8f8a-1adcb2c8dc39 +Content-Type: application/json + +{ + "firstName": "Emiliano", + "middleName": null, + "lastName": "Martínez", + "dateOfBirth": "1992-09-02T00:00:00.000Z", + "squadNumber": 23, + "position": "Goalkeeper", + "abbrPosition": "GK", + "team": "Aston Villa FC", + "league": "Premier League", + "starting11": true +} + +# ------------------------------------------------------------------------------ +# DELETE /players/{player_id} — Delete +# Thiago Almada (squad 16): created by POST above. Since the UUID is generated +# at runtime, retrieve it first via squad number, then substitute it below. +# ------------------------------------------------------------------------------ + +### Step 1 — Look up Almada's UUID by squad number +GET {{baseUrl}}/players/squadnumber/16 +Accept: application/json + +### Step 2 — Delete Almada using the UUID returned above +# Replace {player_id} with the id field from the response above. +DELETE {{baseUrl}}/players/{player_id}