at main 13 kB view raw
1openapi: 3.0.3 2info: 3 title: Banking Demo API 4 version: 1.0.0 5 description: | 6 Minimal spec matching the current Express+SQLite implementation with request/response validation. 7 ⚠️ Demo only: `/cards` returns full PAN + CVV as stored. 8 9servers: 10 - url: http://localhost:3001 11 12components: 13 securitySchemes: 14 BearerAuth: 15 type: http 16 scheme: bearer 17 bearerFormat: JWT 18 19 responses: 20 Error400: 21 description: Bad Request (validation error) 22 content: 23 application/json: 24 schema: 25 $ref: "#/components/schemas/Error" 26 Error401: 27 description: Unauthorized / missing or invalid credentials 28 content: 29 application/json: 30 schema: 31 $ref: "#/components/schemas/Error" 32 Error403: 33 description: Forbidden 34 content: 35 application/json: 36 schema: 37 $ref: "#/components/schemas/Error" 38 Error500: 39 description: Internal Server Error 40 content: 41 application/json: 42 schema: 43 $ref: "#/components/schemas/Error" 44 45 schemas: 46 LoginRequest: 47 type: object 48 required: [username, password] 49 properties: 50 username: 51 type: string 52 example: test@test.test 53 password: 54 type: string 55 example: password@123 56 57 TokenPair: 58 type: object 59 required: [accessToken, refreshToken, expires] 60 properties: 61 accessToken: 62 type: string 63 description: Access JWT (short-lived). 64 refreshToken: 65 type: string 66 description: Refresh JWT (longer-lived). 67 expires: 68 type: string 69 format: date-time 70 description: Access token expiry timestamp (ISO 8601). Present on /login, omitted on /refresh-token. 71 example: "2024-06-01T10:05:00Z" 72 73 RefreshRequest: 74 type: object 75 required: [refreshToken] 76 properties: 77 refreshToken: 78 type: string 79 80 Account: 81 type: object 82 required: [id, user_id, name, iban, balance] 83 properties: 84 id: { type: integer } 85 user_id: { type: integer } 86 iban: { type: string } 87 name: { type: string } 88 balance: 89 type: number 90 format: float 91 description: Calculated from transactions; 0 if none. 92 example: 93 id: 1 94 user_id: 1 95 name: Checking 96 balance: 1680.16 97 98 Card: 99 type: object 100 required: [id, user_id, number, expiry, cvv] 101 properties: 102 id: { type: integer } 103 user_id: { type: integer } 104 number: 105 type: string 106 description: Full PAN (as stored). Returned as-is by the current API. 107 example: "4111111111111111" 108 expiry: { type: string, example: "12/26" } 109 cvv: { type: string, example: "123" } 110 111 PaginationMeta: 112 type: object 113 required: [page, limit, total, hasMore] 114 properties: 115 page: 116 type: integer 117 description: Current page number (1-based) 118 limit: 119 type: integer 120 description: Page size 121 hasMore: 122 type: boolean 123 description: True if there are more pages after the current one 124 total: 125 type: integer 126 description: Total number of matching items 127 128 PaginatedTransactions: 129 type: object 130 required: [data, meta] 131 properties: 132 data: 133 type: array 134 items: 135 $ref: "#/components/schemas/Transaction" 136 meta: 137 $ref: "#/components/schemas/PaginationMeta" 138 139 TransactionType: 140 type: object 141 required: [name, count] 142 properties: 143 name: { type: string } 144 count: { type: integer } 145 146 Transaction: 147 type: object 148 required: [id, userId, accountId, amount, type, description, date] 149 properties: 150 id: { type: integer } 151 userId: { type: integer } 152 accountId: { type: integer } 153 amount: 154 type: number 155 format: float 156 description: Positive for credits, negative for debits. 157 type: 158 type: string 159 description: 160 type: string 161 date: 162 type: string 163 format: date-time 164 description: ISO 8601 timestamp. 165 example: "2024-06-01T10:00:00Z" 166 167 User: 168 type: object 169 required: [id, username, fullname, created] 170 properties: 171 id: 172 type: integer 173 description: Unique user ID 174 example: 2 175 username: 176 type: string 177 description: login/username of the user 178 example: nmokkenstorm 179 fullname: 180 type: string 181 description: government name of the user 182 example: Niels Mokkenstorm 183 created: 184 type: string 185 format: date-time 186 description: ISO 8601 timestamp. 187 example: "2024-06-01T10:00:00Z" 188 189 Error: 190 type: object 191 properties: 192 message: 193 type: string 194 195 LoginError: 196 type: object 197 description: Standard validation/error envelope. 198 required: [errors] 199 properties: 200 errors: 201 type: array 202 description: Non-field/global errors. 203 items: 204 type: string 205 properties: 206 type: object 207 description: Per-field validation errors. 208 properties: 209 username: 210 $ref: "#/components/schemas/FieldError" 211 password: 212 $ref: "#/components/schemas/FieldError" 213 214 example: 215 errors: [] 216 properties: 217 username: 218 errors: ["Invalid email address"] 219 password: 220 errors: ["Too small: expected string to have >=8 characters"] 221 222 FieldError: 223 type: object 224 required: [errors] 225 properties: 226 errors: 227 type: array 228 items: 229 type: string 230 231tags: 232 - name: Meta 233 - name: Auth 234 - name: Accounts 235 - name: Cards 236 - name: Transactions 237 238paths: 239 /: 240 get: 241 summary: Swagger Documentation 242 description: Serves the Swagger UI for this API. 243 tags: [Meta] 244 responses: 245 "200": 246 description: Documentation page 247 content: 248 text/html: 249 schema: 250 type: string 251 252 /openapi.yaml: 253 get: 254 summary: OpenAPI Spec 255 description: Serves the OpenAPI YAML document used by the validator. 256 tags: [Meta] 257 responses: 258 "200": 259 description: OpenAPI spec (YAML) 260 content: 261 application/yaml: 262 schema: 263 type: string 264 /me: 265 get: 266 summary: Retrieves information about the authenticated user 267 tags: [Auth] 268 security: 269 - BearerAuth: [] 270 responses: 271 "200": 272 description: User object 273 content: 274 application/json: 275 schema: 276 $ref: "#/components/schemas/User" 277 "401": 278 $ref: "#/components/responses/Error401" 279 "403": 280 $ref: "#/components/responses/Error403" 281 "500": 282 $ref: "#/components/responses/Error500" 283 /login: 284 post: 285 summary: Login with username and password 286 tags: [Auth] 287 requestBody: 288 required: true 289 content: 290 application/json: 291 schema: 292 $ref: "#/components/schemas/LoginRequest" 293 responses: 294 "200": 295 description: Token pair issued 296 content: 297 application/json: 298 schema: 299 $ref: "#/components/schemas/TokenPair" 300 "400": 301 $ref: "#/components/responses/Error400" 302 "401": 303 description: Invalid credentials 304 content: 305 application/json: 306 schema: 307 $ref: "#/components/schemas/LoginError" 308 "500": 309 $ref: "#/components/responses/Error500" 310 311 /refresh-token: 312 post: 313 summary: Exchange refresh token for new access & refresh tokens 314 tags: [Auth] 315 requestBody: 316 required: true 317 content: 318 application/json: 319 schema: 320 $ref: "#/components/schemas/RefreshRequest" 321 responses: 322 "200": 323 description: New token pair 324 content: 325 application/json: 326 schema: 327 $ref: "#/components/schemas/TokenPair" 328 "400": 329 $ref: "#/components/responses/Error400" 330 "401": 331 $ref: "#/components/responses/Error401" 332 "500": 333 $ref: "#/components/responses/Error500" 334 335 /accounts: 336 get: 337 summary: List accounts for the authenticated user, including calculated balances 338 tags: [Accounts] 339 security: 340 - BearerAuth: [] 341 responses: 342 "200": 343 description: Array of accounts 344 content: 345 application/json: 346 schema: 347 type: array 348 items: 349 $ref: "#/components/schemas/Account" 350 "401": 351 $ref: "#/components/responses/Error401" 352 "403": 353 $ref: "#/components/responses/Error403" 354 "500": 355 $ref: "#/components/responses/Error500" 356 357 /accounts/{accountId}: 358 get: 359 summary: Retrieves a single account for the authenticated user, including calculated balances 360 parameters: 361 - in: path 362 name: accountId 363 schema: 364 type: integer 365 required: true 366 description: Numeric ID of the account to get 367 tags: [Accounts] 368 security: 369 - BearerAuth: [] 370 responses: 371 "200": 372 description: Account object 373 content: 374 application/json: 375 schema: 376 $ref: "#/components/schemas/Account" 377 "401": 378 $ref: "#/components/responses/Error401" 379 "403": 380 $ref: "#/components/responses/Error403" 381 "500": 382 $ref: "#/components/responses/Error500" 383 384 /cards: 385 get: 386 summary: List stored cards for the authenticated user 387 description: Returns full PAN and CVV as currently implemented. **Do not use in production.** 388 tags: [Cards] 389 security: 390 - BearerAuth: [] 391 responses: 392 "200": 393 description: Array of cards 394 content: 395 application/json: 396 schema: 397 type: array 398 items: 399 $ref: "#/components/schemas/Card" 400 "401": 401 $ref: "#/components/responses/Error401" 402 "403": 403 $ref: "#/components/responses/Error403" 404 "500": 405 $ref: "#/components/responses/Error500" 406 407 /transaction-types: 408 get: 409 summary: Find transaction types for the authenticated user 410 tags: [Transactions] 411 security: 412 - BearerAuth: [] 413 parameters: 414 - in: query 415 name: accountId 416 schema: 417 type: integer 418 description: Filter by account ID 419 responses: 420 "200": 421 description: Array of transaction types 422 content: 423 application/json: 424 schema: 425 type: array 426 items: 427 $ref: "#/components/schemas/TransactionType" 428 "400": 429 $ref: "#/components/responses/Error400" 430 "401": 431 $ref: "#/components/responses/Error401" 432 "403": 433 $ref: "#/components/responses/Error403" 434 "500": 435 $ref: "#/components/responses/Error500" 436 437 /transactions: 438 get: 439 summary: Search/sort/paginate transactions for the authenticated user 440 tags: [Transactions] 441 security: 442 - BearerAuth: [] 443 parameters: 444 - in: query 445 name: search 446 schema: 447 type: string 448 description: Case-insensitive LIKE search against description and type. 449 example: Shopping 450 - in: query 451 name: sort 452 schema: 453 type: string 454 default: date 455 description: Column to sort by (free-form; current API does not enforce an allowlist). 456 example: date 457 - in: query 458 name: order 459 schema: 460 type: string 461 default: desc 462 enum: [asc, desc] 463 - in: query 464 name: page 465 schema: 466 type: integer 467 default: 1 468 minimum: 1 469 - in: query 470 name: limit 471 schema: 472 type: integer 473 default: 25 474 description: Page size 475 - in: query 476 name: accountId 477 schema: 478 type: integer 479 description: Filter by account ID 480 - in: query 481 name: type 482 schema: 483 type: string 484 description: Filter by transaction type (withdrawal, deposit, etc.) 485 responses: 486 "200": 487 description: Array of transactions (page slice) 488 content: 489 application/json: 490 schema: 491 $ref: "#/components/schemas/PaginatedTransactions" 492 "400": 493 $ref: "#/components/responses/Error400" 494 "401": 495 $ref: "#/components/responses/Error401" 496 "403": 497 $ref: "#/components/responses/Error403" 498 "500": 499 $ref: "#/components/responses/Error500"