TypeScript 98.5%
HTML 0.8%
JavaScript 0.5%
Dockerfile 0.2%
9 1 0

Clone this repository

https://tangled.org/mokkenstorm.dev/react-native-demo
git@tangled.org:mokkenstorm.dev/react-native-demo

For self-hosted knots, clone URLs may differ based on your setup.

README.md

BankingMockAPI#

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.


🚀 Getting Started#

Prerequisites#

  • Node.js v18 or higher

  • Docker (optional, for containerized setup)

  • Expo CLI (for running the React Native app):

    npm install -g expo
    

Installation#

git clone git@tangled.sh:mokkenstorm.dev/react-native-demo
cd react-native-demo

Running the Server#

Run directly with Node.js#

cd server && npx ts-node src/server.ts

The server will be available at:
👉 http://localhost:3001

Run with Docker Compose#

docker compose up --build

Stop the service:

docker compose down

Server base URL: http://localhost:3001


🎨 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:

cd app
npm run generate
npm run ios

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:


📖 API Endpoints#

All protected routes require a JWT in the Authorization header:

Authorization: Bearer <JWT>

🔑 Authentication#

POST /login#

Authenticate and receive a token pair.

Request Body

{
  "username": "test@test.test",
  "password": "password@123"
}

Response 200**

{
  "accessToken": "<JWT>",
  "refreshToken": "<refresh_JWT>",
  "expires": "2024-06-01T10:05:00Z"
}

Response 401**

{
  "errors": [],
  "properties": {
    "username": { "errors": ["Invalid email address"] },
    "password": {
      "errors": ["Too small: expected string to have >=8 characters"]
    }
  }
}

POST /refresh-token#

Exchange a refresh token for a new pair.

Request Body

{
  "refreshToken": "<refresh_JWT>"
}

Response 200**

{
  "accessToken": "<new_JWT>",
  "refreshToken": "<new_refresh_JWT>"
}

👤 Me#

GET /me#

Returns the authenticated user.

Response 200**

{
  "id": 2,
  "username": "nmokkenstorm",
  "fullname": "Niels Mokkenstorm",
  "created": "2024-06-01T10:00:00Z"
}

🏦 Accounts#

GET /accounts#

List accounts for the authenticated user.

Response 200**

[
  {
    "id": 1,
    "user_id": 1,
    "iban": "NL00BANK0123456789",
    "name": "Checking",
    "balance": 1680.16
  }
]

GET /accounts/{accountId}#

Retrieve a single account by ID.

Response 200**

{
  "id": 1,
  "user_id": 1,
  "iban": "NL00BANK0123456789",
  "name": "Checking",
  "balance": 1680.16
}

💳 Cards#

GET /cards#

List stored cards (demo only: returns full PAN and CVV).

Response 200**

[
  {
    "id": 1,
    "user_id": 1,
    "number": "4111111111111111",
    "expiry": "12/26",
    "cvv": "123"
  }
]

🧾 Transactions#

GET /transactions#

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**

{
  "data": [
    {
      "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.

Response 200**

[
  { "name": "debit", "count": 12 },
  { "name": "credit", "count": 5 }
]

👤 Default Test User#

  • Username: test@test.test
  • Password: password@123

🗄️ Database#

  • Uses SQLite.
  • The database is reset and seeded with test data on every server start.