Skip to content

d0sadata/node-test

Repository files navigation

Branches API (Backend Coding Task)

Tiny TypeScript/Node.js API for browsing bank branches. Designed to be easy for a frontend/mobile client to consume.

Tech

  • Node.js + TypeScript
  • Express
  • Zod for input validation
  • Jest + Supertest for tests
  • Optional Firebase Cloud Function wrapper

Quickstart

npm install
npm run dev

Server runs on http://localhost:7000 by default.

Other useful commands

npm test
npm run build
npm start

Postman collection

A Postman collection is included at postman/branches_api.postman_collection.json.

  • Import it into Postman
  • Ensure baseUrl is set (default: http://localhost:7000)
  • Run the requests (the pagination request stores a branchId variable for the /branches/:id request)
  • The collection also includes ATM-related branch filters and /branches/:id/atms requests

API

Health check

GET /health

Response:

{ "status": "ok" }

List branches

GET /branches

Query parameters:

  • city (string, optional): filter by city (case-insensitive exact match)
  • open (true | false, optional): when true, returns branches that are open “right now” based on today’s hours
  • includeAtms (true | false, optional, default false): when true, embeds the atms array in each branch item (otherwise only ATM counts are returned)
  • hasAtm (true | false, optional): filter branches that have (or do not have) ATMs
  • atmDeposit (true | false, optional): filter branches that have at least one deposit-capable ATM
  • atmAccessible (true | false, optional): filter branches that have at least one accessible ATM
  • page (number as string, optional, default 1): must be > 0
  • limit (number as string, optional, default 20): must be 1..100

Response shape:

{
 "total": 1,
 "page": 1,
 "limit": 20,
 "items": [
  {
   "id": "b1",
   "name": "Alexanderplatz Branch",
   "address": "Alexanderplatz 5",
   "city": "Berlin",
   "location": { "lat": 52.5219, "lon": 13.4132 },
    "atmCount": 2,
    "depositAtmCount": 1,
    "accessibleAtmCount": 1,
    "inServiceAtmCount": 1,
   "hours": {
    "mon": "09:00-18:00",
    "tue": "09:00-18:00",
    "wed": "09:00-18:00",
    "thu": "09:00-18:00",
    "fri": "09:00-18:00",
    "sat": "10:00-16:00",
    "sun": "Closed"
   }
  }
 ]
}

Examples:

  • GET /branches?city=Berlin
  • GET /branches?page=2&limit=10
  • GET /branches?open=true
  • GET /branches?includeAtms=true
  • GET /branches?hasAtm=true
  • GET /branches?atmDeposit=true

Get single branch

GET /branches/:id

  • 200: branch object
  • 404: { "status": 404, "message": "Not found" }

List ATMs for a branch

GET /branches/:id/atms

Query parameters:

  • deposit (true | false, optional)
  • accessible (true | false, optional)
  • inService (true | false, optional)
  • page / limit (same rules as branches)

Response shape:

{
    "total": 2,
    "page": 1,
    "limit": 20,
    "items": [
        {
            "id": "atm-b1-1",
            "location": { "lat": 52.52195, "lon": 13.41315 },
            "availability": "in_service",
            "supportsCashWithdrawal": true,
            "supportsDeposit": true,
            "accessible": true
        }
    ]
}

List ATMs (all branches)

GET /atms

This endpoint is frontend-oriented: each ATM includes the branch context needed to show it in a list/map UI.

Query parameters:

  • city (string, optional)
  • near (lat,lon string, optional): example 52.5219,13.4132
  • radiusKm (number as string, optional): requires near; filters results within the given radius
  • deposit (true | false, optional)
  • accessible (true | false, optional)
  • inService (true | false, optional)
  • page / limit (same rules as branches)

Response shape:

{
    "total": 3,
    "page": 1,
    "limit": 20,
    "items": [
        {
            "id": "atm-b1-1",
            "location": { "lat": 52.52195, "lon": 13.41315 },
            "distanceKm": 0.01,
            "availability": "in_service",
            "supportsCashWithdrawal": true,
            "supportsDeposit": true,
            "accessible": true,
            "branch": {
                "id": "b1",
                "name": "Alexanderplatz Branch",
                "address": "Alexanderplatz 5",
                "city": "Berlin",
                "location": { "lat": 52.5219, "lon": 13.4132 }
            }
        }
    ]
}

Notes:

  • When near is provided, items are sorted by distanceKm ascending.
  • distanceKm is only included when near is provided.

Error handling

  • Validation errors return 400 with { status: 400, message: "Validation error", details: [...] }
  • Unknown errors return 500 with { status: 500, message: "Internal server error" }

Data source

Branch data is loaded from a static JSON file: branches-api/src/data/branches.json.

Firebase (optional)

If you want to run this as a Firebase HTTPS function, there is a wrapper at branches-api/functions/src/index.ts:

  • exported function name: api

No deployment is required for this task; local execution is sufficient.

Project structure

  • branches-api/src/app.ts: Express app setup + routes + error handler
  • branches-api/src/routes: route definitions
  • branches-api/src/controllers: request handlers
  • branches-api/src/services: data access / business logic
  • branches-api/src/middleware: validation + error handling
  • branches-api/src/__tests__: Jest/Supertest integration tests

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors