diff --git a/README.md b/README.md index 14ac395..baf6504 100644 --- a/README.md +++ b/README.md @@ -1,174 +1,308 @@ # BankingMockAPI -## Getting Started +A simple mock banking API for testing and prototyping. +Provides authentication, accounts, cards, and transactions endpoints backed by a seeded SQLite database. +Includes a React Native demo app powered by [Expo](https://expo.dev/). + +--- + +## ๐Ÿš€ Getting Started ### Prerequisites -- [Node.js](https://nodejs.org/) (v18 or higher) +- [Node.js](https://nodejs.org/) **v18 or higher** - [Docker](https://www.docker.com/) (optional, for containerized setup) +- [Expo CLI](https://docs.expo.dev/get-started/installation/) (for running the React Native app): -### Installation + ```bash + npm install -g expo + ``` + +--- -1. Clone the repository: +### Installation ```bash -git clone -cd BankingMockAPI +git clone git@tangled.sh:mokkenstorm.dev/react-native-demo +cd react-native-demo ``` -2. Install dependencies: - - ```bash - npm install - ``` +--- ### Running the Server -#### With Node.js +#### Run directly with Node.js ```bash -node server.js +cd server && npx ts-node src/server.ts ``` -The server will start on [http://localhost:3001](http://localhost:3001) by default. +The server will be available at: +๐Ÿ‘‰ `http://localhost:3001` + +#### Run with Docker Compose + +```bash +docker compose up --build +``` -#### With Docker +Stop the service: ```bash -docker build -t banking-mock-api . -docker run --name banking-mock-api -d -p 3001:3001 banking-mock-api +docker compose down ``` -Same as mentioned aboe the api will be available at on [http://localhost:3001](http://localhost:3001) +Server base URL: `http://localhost:3001` + +--- -Use following commands to stop or start the container: +### ๐ŸŽจ Running the App + +The repository includes a React Native demo app that connects to the API. + +To generate client code from the OpenAPI spec and start the app with Expo: ```bash -docker container stop banking-mock-api -docker container start banking-mock-api +cd app +npm run generate +npm run ios ``` -## API Endpoints +You can replace `npm run ios` with: + +- `npm run android` โ€” to run on Android +- `npm run web` โ€” to run in a web browser + +โš ๏ธ **Note:** The app requires and **API server** (see instructions above). +Without the server running on `http://localhost:3001`, login and data +fetches will fail by default. If you need a different backend port/url +and set the `SERVER_URL` environment variable before generating the +client code, and optionally configure the `compose.yaml` for a different port. + +Expo will guide you through launching the app on your chosen platform. + +--- + +## ๐Ÿ“š API Documentation + +Interactive documentation and the raw OpenAPI specification are exposed by the server: + +- **Swagger UI:** + [http://localhost:3001](http://localhost:3001) + A browsable interface to test and explore the API endpoints. + +- **OpenAPI Spec (YAML):** + [http://localhost:3001/openapi.yaml](http://localhost:3001/openapi.yaml) + The raw machine-readable specification, suitable for client generation. + +--- -### Authentication +## ๐Ÿ“– API Endpoints + +All protected routes require a **JWT** in the `Authorization` header: + +```bash +Authorization: Bearer +``` + +### ๐Ÿ”‘ Authentication #### `POST /login` -Authenticate user and receive JWT and refresh token. +Authenticate and receive a token pair. -- **Body:** +**Request Body** - ```json - { - "username": "test@test.test", - "password": "password@123" - } - ``` -- **Response:** - ```json - { - "token": "", - "refreshToken": "" +```json +{ + "username": "test@test.test", + "password": "password@123" +} +``` + +Response 200\*\* + +```json +{ + "accessToken": "", + "refreshToken": "", + "expires": "2024-06-01T10:05:00Z" +} +``` + +Response 401\*\* + +```json +{ + "errors": [], + "properties": { + "username": { "errors": ["Invalid email address"] }, + "password": { + "errors": ["Too small: expected string to have >=8 characters"] + } } - ``` +} +``` + +--- #### `POST /refresh-token` -Get a new JWT using a refresh token. +Exchange a refresh token for a new pair. -- **Body:** - ```json - { - "refreshToken": "" - } - ``` -- **Response:** - ```json +**Request Body** + +```json +{ + "refreshToken": "" +} +``` + +Response 200\*\* + +```json +{ + "accessToken": "", + "refreshToken": "" +} +``` + +--- + +### ๐Ÿ‘ค Me + +#### `GET /me` + +Returns the authenticated user. + +Response 200\*\* + +```json +{ + "id": 2, + "username": "nmokkenstorm", + "fullname": "Niels Mokkenstorm", + "created": "2024-06-01T10:00:00Z" +} +``` + +--- + +### ๐Ÿฆ Accounts + +#### `GET /accounts` + +List accounts for the authenticated user. + +Response 200\*\* + +```json +[ { - "token": "", - "refreshToken": "" + "id": 1, + "user_id": 1, + "iban": "NL00BANK0123456789", + "name": "Checking", + "balance": 1680.16 } - ``` +] +``` -### Accounts +#### `GET /accounts/{accountId}` -#### `GET /accounts` +Retrieve a single account by ID. -Get all accounts for the authenticated user. +Response 200\*\* -- **Headers:** - - `Authorization: Bearer ` -- **Response:** - ```json - [ - { - "id": 1, - "user_id": 1, - "name": "Checking", - "balance": 1500.5 - }, - ... - ] - ``` +```json +{ + "id": 1, + "user_id": 1, + "iban": "NL00BANK0123456789", + "name": "Checking", + "balance": 1680.16 +} +``` + +--- -### Cards +### ๐Ÿ’ณ Cards #### `GET /cards` -Get all cards for the authenticated user. +List stored cards (**demo only**: returns full PAN and CVV). -- **Headers:** - - `Authorization: Bearer ` -- **Response:** - ```json - [ - { - "id": 1, - "user_id": 1, - "number": "4111111111111111", - "expiry": "12/26", - "cvv": "123" - }, - ... - ] - ``` +Response 200\*\* + +```json +[ + { + "id": 1, + "user_id": 1, + "number": "4111111111111111", + "expiry": "12/26", + "cvv": "123" + } +] +``` -### Transactions +--- + +### ๐Ÿงพ Transactions #### `GET /transactions` -Get transactions for the authenticated user, with search, sort, and pagination. - -- **Headers:** - - `Authorization: Bearer ` -- **Query Parameters:** - - `search` (optional): Search by description or type - - `sort` (optional): Field to sort by (default: `date`) - - `order` (optional): `asc` or `desc` (default: `desc`) - - `page` (optional): Page number (default: `1`) - - `limit` (optional): Items per page (default: `10`) -- **Response:** - ```json - [ +Search/sort/paginate transactions. Query params: `search`, `sort` (default `date`), `order` (`asc|desc`, default `desc`), `page` (default `1`), `limit` (default `25`), `accountId`, `type`. + +Response 200\*\* + +```json +{ + "data": [ { "id": 1, - "user_id": 1, - "account_id": 1, + "userId": 1, + "accountId": 1, "amount": -50.25, "type": "debit", "description": "Grocery Store", "date": "2024-06-01T10:00:00Z" - }, - ... - ] - ``` + } + ], + "meta": { + "page": 1, + "limit": 25, + "hasMore": false, + "total": 1 + } +} +``` + +--- + +#### `GET /transaction-types` + +Aggregate transaction types. -## Default Test User +Response 200\*\* + +```json +[ + { "name": "debit", "count": 12 }, + { "name": "credit", "count": 5 } +] +``` + +--- + +## ๐Ÿ‘ค Default Test User - **Username:** `test@test.test` - **Password:** `password@123` -## Database +--- + +## ๐Ÿ—„๏ธ Database -- The SQLite database is used. -- The database is reset and seeded with test data every time the server starts. +- Uses **SQLite**. +- The database is reset and seeded with test data on every server start. diff --git a/app/openapi-ts.config.ts b/app/openapi-ts.config.ts index bff2f7b..39d3241 100644 --- a/app/openapi-ts.config.ts +++ b/app/openapi-ts.config.ts @@ -1,7 +1,7 @@ import { defineConfig } from "@hey-api/openapi-ts"; export default defineConfig({ - input: "http://localhost:3001/openapi.yaml", + input: process.env.SERVER_URL || "http://localhost:3001/openapi.yaml", output: "generated", plugins: [ "@tanstack/react-query",