|
| 1 | +# API Reference |
| 2 | + |
| 3 | +## Base URL |
| 4 | + |
| 5 | +Local and CI smoke tests reach the API through NGINX: |
| 6 | + |
| 7 | +```text |
| 8 | +http://localhost:9999 |
| 9 | +``` |
| 10 | + |
| 11 | +The production compose file exposes the same public entrypoint on port `9999`. |
| 12 | + |
| 13 | +## Client IDs and limits |
| 14 | + |
| 15 | +The implementation has five predefined clients. The API keeps this small map in memory for fast invalid-client rejection, and PostgreSQL seeds the same limits in `docker-entrypoint-initdb.d/rinha.dump.sql`. |
| 16 | + |
| 17 | +| Client ID | Limit, in cents | |
| 18 | +|---:|---:| |
| 19 | +| `1` | `100000` | |
| 20 | +| `2` | `80000` | |
| 21 | +| `3` | `1000000` | |
| 22 | +| `4` | `10000000` | |
| 23 | +| `5` | `500000` | |
| 24 | + |
| 25 | +## `POST /clientes/{id}/transacoes` |
| 26 | + |
| 27 | +Submits a credit or debit transaction. |
| 28 | + |
| 29 | +### Request body |
| 30 | + |
| 31 | +```json |
| 32 | +{ |
| 33 | + "valor": 1000, |
| 34 | + "tipo": "c", |
| 35 | + "descricao": "deposito" |
| 36 | +} |
| 37 | +``` |
| 38 | + |
| 39 | +| Field | Type | Rule | |
| 40 | +|---|---|---| |
| 41 | +| `valor` | integer | Required positive integer amount in cents (`> 0`) | |
| 42 | +| `tipo` | string | Required; `"c"` for credit or `"d"` for debit | |
| 43 | +| `descricao` | string | Required, non-empty, maximum 10 characters | |
| 44 | + |
| 45 | +### Successful response |
| 46 | + |
| 47 | +The response uses `snake_case` JSON output generated by `System.Text.Json` source generation. |
| 48 | + |
| 49 | +```json |
| 50 | +{ |
| 51 | + "id": 1, |
| 52 | + "limite": 100000, |
| 53 | + "saldo": 1000 |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +### Status codes |
| 58 | + |
| 59 | +| Status | When | |
| 60 | +|---:|---| |
| 61 | +| `200` | Transaction accepted and a balance is returned | |
| 62 | +| `404` | Client ID is not one of `1` through `5` | |
| 63 | +| `422` | Payload validation fails (`valor <= 0`, invalid `tipo`, missing/empty/long `descricao`) | |
| 64 | + |
| 65 | +### Current implementation note |
| 66 | + |
| 67 | +The intended Rinha contract treats a debit that would exceed the client's limit as an unprocessable transaction. The current PostgreSQL function keeps the balance unchanged and returns the current balance when the limit update fails, so the API can return `200` with an unchanged balance for this case. If strict challenge behavior is required, adjust `InsertTransacao`/the route handler before documenting over-limit debits as guaranteed `422` responses. |
| 68 | + |
| 69 | +## `GET /clientes/{id}/extrato` |
| 70 | + |
| 71 | +Returns the current account statement. |
| 72 | + |
| 73 | +### Successful response |
| 74 | + |
| 75 | +```json |
| 76 | +{ |
| 77 | + "saldo": { |
| 78 | + "total": 1000, |
| 79 | + "limite": 100000, |
| 80 | + "data_extrato": "2026-04-01T19:20:20.000000" |
| 81 | + }, |
| 82 | + "ultimas_transacoes": [ |
| 83 | + { |
| 84 | + "valor": 1000, |
| 85 | + "tipo": "c", |
| 86 | + "descricao": "deposito" |
| 87 | + } |
| 88 | + ] |
| 89 | +} |
| 90 | +``` |
| 91 | + |
| 92 | +The statement returns the latest 10 transactions ordered from newest to oldest. |
| 93 | + |
| 94 | +### Status codes |
| 95 | + |
| 96 | +| Status | When | |
| 97 | +|---:|---| |
| 98 | +| `200` | Client exists and statement data was returned | |
| 99 | +| `404` | Client ID is not one of `1` through `5` | |
| 100 | + |
| 101 | +## `GET /healthz` |
| 102 | + |
| 103 | +Health check used by local smoke tests and GitHub Actions. |
| 104 | + |
| 105 | +| Status | When | |
| 106 | +|---:|---| |
| 107 | +| `200` | ASP.NET Core health checks pass | |
| 108 | + |
| 109 | +## Responsibility split |
| 110 | + |
| 111 | +| Layer | Responsibility | |
| 112 | +|---|---| |
| 113 | +| API (`Program.cs`) | Route mapping, JSON serialization, payload validation, fast invalid-client checks, database calls | |
| 114 | +| PostgreSQL (`rinha.dump.sql`) | Seed clients, keep balances, apply atomic balance updates, insert transaction rows, return recent statement data | |
| 115 | +| NGINX (`nginx.conf`) | Public port `9999` and load balancing across the two API instances | |
0 commit comments