Purpose of this page
List every endpoint this API exposes, who's allowed to call it, and what a request and response look like for each.
Resources at a glance the map
| Resource | Base path | Reading it | Changing it |
|---|---|---|---|
| Auth | /api/auth | public (register, login) | n/a — see Section 2 |
| Elements | /api/elements | any logged-in user | Admin only |
| Alloys | /api/alloys | any logged-in user | Admin only |
| Alloy Elements | /api/alloy-elements | any logged-in user | Admin only |
| Coins | /api/coins | any logged-in user | Admin only |
/health metals_api/app.py
The one route defined directly in app.py rather than a blueprint — no /api prefix, no authentication, and deliberately no database access. It returns {"status":"ok"} with 200 whenever the HTTP server is running.
It answers one question: “is this process serving HTTP?” If it also checked the database, a brief database blip would mark the container unhealthy and trigger a restart — restarting a perfectly healthy API for a problem it can't fix. Deeper dependency checks belong in monitoring, not in a liveness probe.
- The image's own HEALTHCHECK, so Docker knows the container's status.
- Compose's depends_on: condition: service_healthy, which holds the UI back until the API answers.
- Azure's healthCheckPath, and the /health polling every deployment path does before declaring success.
The UI container exposes its own /health too — answered by Nginx directly, with no application code involved.
/api/elements metals_api/routes/element_routes.py
Chemical elements, keyed by atomic number.
| Method & path | Who can call it | What it does |
|---|---|---|
| GET /api/elements | any logged-in user | List elements. Optional ?name= and ?color= query filters. |
| GET /api/elements/<atomic_number> | any logged-in user | Get one element, or 404 if it doesn't exist. |
| POST /api/elements | Admin | Create an element. |
| PUT /api/elements/<atomic_number> | Admin | Update one or more fields on an existing element. |
| DELETE /api/elements/<atomic_number> | Admin | Delete an element, or 404 if it doesn't exist. |
{
"atomic_number": 3,
"name": "Lithium",
"symbol": "Li",
"melting_point_f": 356.9,
"boiling_point_f": 2447.6,
"color": "silvery",
"density": 0.53,
"category": "ALKALI_METAL",
"state_at_room_temp": "SOLID",
"is_toxic": false,
"is_magnetic": false,
"common_uses": "batteries"
}
Only atomic_number, name, and symbol are required; everything else is optional. Sending an unrecognized field, or a field of the wrong shape (like a negative density, or a state_at_room_temp outside SOLID / LIQUID / GAS), returns 400 before anything is written — see how errors are reported below.
{
"atomic_number": 3,
"name": "Lithium",
"symbol": "Li",
"melting_point_f": 356.9,
"boiling_point_f": 2447.6,
"color": "silvery",
"density": 0.53,
"category": "ALKALI_METAL",
"state_at_room_temp": "SOLID",
"is_toxic": false,
"is_magnetic": false,
"common_uses": "batteries"
}
/api/alloys metals_api/routes/alloy_routes.py
Named mixtures, like “Sterling Silver.”
| Method & path | Who can call it | What it does |
|---|---|---|
| GET /api/alloys | any logged-in user | List alloys. Optional ?name= and ?color= query filters. |
| GET /api/alloys/<alloy_id> | any logged-in user | Get one alloy, or 404. |
| POST /api/alloys | Admin | Create an alloy. Requires name; color and description are optional. |
| PUT /api/alloys/<alloy_id> | Admin | Update one or more fields. |
| DELETE /api/alloys/<alloy_id> | Admin | Delete an alloy, or 404. |
// POST /api/alloys
{ "name": "Fine Gold 24K", "color": "gold", "description": "High-purity investment gold." }
/api/alloy-elements metals_api/routes/alloy_element_routes.py
The join table between alloys and elements — what percentage of a given alloy each element makes up. This is the one resource identified by two path values instead of one, matching its composite primary key.
| Method & path | Who can call it | What it does |
|---|---|---|
| GET /api/alloy-elements | any logged-in user | List, filterable by ?alloy_id= and/or ?atomic_number=. |
| GET /api/alloy-elements/<alloy_id>/<atomic_number> | any logged-in user | Get one composition row, or 404. |
| POST /api/alloy-elements | Admin | Add an element to an alloy with a given percent_of_alloy. |
| PUT /api/alloy-elements/<alloy_id>/<atomic_number> | Admin | Change the percent_of_alloy for that pair. |
| DELETE /api/alloy-elements/<alloy_id>/<atomic_number> | Admin | Remove that element from that alloy. |
// POST /api/alloy-elements
{ "alloy_id": 6, "atomic_number": 47, "percent_of_alloy": 92.5 }
/api/coins metals_api/routes/coin_routes.py
Real-world coins, each minted from exactly one alloy.
| Method & path | Who can call it | What it does |
|---|---|---|
| GET /api/coins | any logged-in user | List, filterable by ?name=, ?country=, and/or ?alloy_id=. |
| GET /api/coins/<coin_id> | any logged-in user | Get one coin, or 404. |
| POST /api/coins | Admin | Create a coin. Requires name and alloy_id (must reference an existing alloy). |
| PUT /api/coins/<coin_id> | Admin | Update one or more fields. |
| DELETE /api/coins/<coin_id> | Admin | Delete a coin, or 404. |
// POST /api/coins
{
"name": "American Gold Eagle (1 oz)",
"country": "United States",
"mint": "United States Mint",
"year_introduced": 1986,
"alloy_id": 2,
"gross_weight_g": 33.9305,
"face_value": 50.00,
"face_value_currency_code": "USD"
}
How errors are reported consistent across every endpoint
Every route validates the request before touching the database, then lets the service layer enforce business rules. Both layers report problems the same way, so client code only needs to handle one shape of error response.
| Status | Body shape | When it happens |
|---|---|---|
400 Bad Request | {"errors": ["..."]} | The request body failed DTO validation (missing/invalid fields), or a business rule was broken (e.g. a duplicate element name). |
401 Unauthorized | {"error": "..."} | No Authorization header, or the token is missing/invalid/expired. See Section 2. |
403 Forbidden | {"error": "You do not have permission to perform this action."} | You're logged in, but your token's roles don't include Admin, and this is a write endpoint. |
404 Not Found | {"error": "... not found"} | The requested id (or id pair, for alloy elements) doesn't exist. |
204 No Content | (empty body) | A DELETE succeeded. |