Skip to content

nanotaboada/ts-node-samples-express-restful

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1,089 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

πŸ§ͺ RESTful API with Node.js and Express.js in TypeScript

Node.js CI Node.js CD CodeQL Advanced Quality Gate Status codecov CodeFactor License: MIT Dependabot Copilot Claude CodeRabbit

Proof of Concept for a RESTful Web Service built with Express.js 5 and TypeScript targeting Node.js 24 LTS. This project demonstrates best practices for building a layered, testable, and maintainable API implementing CRUD operations for a Players resource (Argentina 2022 FIFA World Cup squad).

Features

  • πŸ—οΈ Layered Architecture - Interface-based design with constructor injection and strict TypeScript
  • πŸ“š Interactive Documentation - Live API exploration with Swagger UI and VS Code REST Client support
  • ⚑ Performance Caching - In-memory caching with node-cache and Sequelize ORM
  • πŸ”’ Security Middleware - Rate limiting, CORS, and Helmet headers
  • 🐳 Containerized Deployment - Multi-stage Docker builds with pre-seeded database
  • πŸ”„ Automated Pipeline - Continuous integration with ESLint, Prettier, and automated testing

Tech Stack

Category Technology
Runtime Node.js 24 (LTS/Krypton)
Language TypeScript 5.9
Module System Native ECMAScript Modules (ESM) - uses tsx for execution
Framework Express.js 5
Database SQLite3 with Sequelize ORM
Caching node-cache
Documentation Swagger (OpenAPI 3.0)
Security Helmet, CORS, express-rate-limit
Testing Jest 30 with Supertest
Containerization Docker with multi-stage builds
Code Quality ESLint, Prettier, Commitlint
Dev Tools tsx (TypeScript executor), nodemon

πŸ’‘ Note: While the repository name references ts-node (the original implementation), the project now uses tsx for faster, cleaner TypeScript execution without experimental flags.

Architecture

Layered architecture with dependency injection via constructors and interface-based contracts.

%%{init: {
  "theme": "default",
  "themeVariables": {
    "fontFamily": "Fira Code, Consolas, monospace",
    "textColor": "#555",
    "lineColor": "#555",
    "lineWidth": 2,
    "clusterBkg": "#f5f5f5",
    "clusterBorder": "#999"
  }
}}%%

graph RL

    tests[tests]

    subgraph Layer 1[" "]
        server[server]
        app[app]
    end

    subgraph Layer 2[" "]
        routes[routes]
        controllers[controllers]
        Express[Express]
    end

    subgraph Layer 3[" "]
        services[services]
        nodeCache[node-cache]
    end

    subgraph Layer 4[" "]
        database[database]
        Sequelize[Sequelize]
    end

    models[models]

    %% Dependencies

    app --> server
    routes --> app
    controllers --> routes
    services --> controllers
    database --> services

    Express --> routes
    nodeCache --> services
    Sequelize --> database

    Express --> app
    Express -.-> controllers
    Sequelize -.-> models

    app -.-> tests

    models -.-> database
    models -.-> services
    models -.-> controllers

    controllers --> app
    services --> app
    database --> app

    %% Styling
    classDef core fill:#b3d9ff,stroke:#6db1ff,stroke-width:2px,color:#555,font-family:monospace;
    classDef deps fill:#ffcccc,stroke:#ff8f8f,stroke-width:2px,color:#555,font-family:monospace;
    classDef test fill:#ccffcc,stroke:#53c45e,stroke-width:2px,color:#555,font-family:monospace;

    class server,app,routes,controllers,services,database,models core
    class Express,Sequelize,nodeCache deps
    class tests test
Loading

Arrows follow the injection direction (A β†’ B means A is injected into B). Solid = runtime dependency, dotted = structural. Blue = core domain, red = third-party, green = tests.

Significant architectural decisions are documented in docs/adr/.

API Reference

Interactive API documentation is available via Swagger UI at http://localhost:9000/swagger/ when the server is running.

Method Endpoint Description Status
GET /players List all players 200 OK
GET /players/:id Get player by ID 200 OK
GET /players/squadNumber/:squadNumber Get player by squad number 200 OK
POST /players Create new player 201 Created
PUT /players/squadNumber/:squadNumber Update player by squad number 204 No Content
DELETE /players/squadNumber/:squadNumber Remove player by squad number 204 No Content
GET /health Health check 200 OK

Error codes: 400 Bad Request (validation failed) Β· 404 Not Found (player not found) Β· 409 Conflict (duplicate squad number on POST)

For complete endpoint documentation with request/response schemas, explore the interactive Swagger UI. You can also access the OpenAPI JSON specification at http://localhost:9000/swagger.json.

Alternatively, use rest/players.rest with the REST Client extension for VS Code to send requests directly from the editor.

Prerequisites

Before you begin, ensure you have the following installed:

  • Node.js (see .nvmrc for required version)
  • npm (comes with Node.js)
  • direnv (optional, but recommended β€” auto-loads the correct Node.js version via .nvmrc on directory entry)
  • Docker and Docker Compose (optional, for containerized setup)

Quick Start

Clone

git clone https://github.com/nanotaboada/ts-node-samples-express-restful.git
cd ts-node-samples-express-restful

Install

npm install

Run

npm run dev

The server will start on http://localhost:9000 with the following output:

> ts-node-samples-express-restful@1.0.0 dev
> nodemon

[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): src/**/*
[nodemon] watching extensions: ts
[nodemon] starting `tsx ./src/server.ts`
πŸš€ Running at http://localhost:9000

Access

Once the application is running, you can access:

  • API Server: http://localhost:9000
  • Swagger UI: http://localhost:9000/swagger/
  • Health Check: http://localhost:9000/health

Containers

Build and Start

npm run docker:up
# or
docker compose up

πŸ’‘ Note: On first run, the container copies a pre-seeded SQLite database into a persistent volume. On subsequent runs, that volume is reused and the data is preserved.

Stop

npm run docker:down
# or
docker compose down

Reset Database

To remove the volume and reinitialize the database from the built-in seed file:

docker compose down -v

Pull Docker Images

Each release publishes multiple tags for flexibility:

# By semantic version (recommended for production)
docker pull ghcr.io/nanotaboada/ts-node-samples-express-restful:1.0.0

# By term name (memorable alternative)
docker pull ghcr.io/nanotaboada/ts-node-samples-express-restful:assist

# Latest release
docker pull ghcr.io/nanotaboada/ts-node-samples-express-restful:latest

Environment Variables

Create a .env file in the root directory to customize configuration:

# Server port (default: 9000)
PORT=9000

# Database storage path (default: storage/players-sqlite3.db)
STORAGE_PATH=storage/players-sqlite3.db

# Rate limiting (all optional β€” defaults shown)
RATE_LIMIT_ENABLED=true
RATE_LIMIT_WINDOW_MS=60000
RATE_LIMIT_MAX_GENERAL=100
RATE_LIMIT_MAX_STRICT=20

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details on:

  • Code of Conduct
  • Development workflow and best practices
  • Commit message conventions (Conventional Commits)
  • Pull request process and requirements

Key guidelines:

  • Follow Conventional Commits for commit messages
  • Ensure all tests pass (npm test)
  • Run linter before committing (npm run lint)
  • Keep changes small and focused
  • Review .github/copilot-instructions.md for architectural patterns

Testing:

Run the test suite with Jest + Supertest:

# Run all tests
npm test

# Run tests with coverage report
npm run coverage

Command Summary

Command Description
npm run dev Start development server with hot reload
npm start Run compiled application from dist/
npm run build Compile TypeScript to JavaScript
npm test Run Jest tests
npm run coverage Generate test coverage report
npm run lint Run ESLint on all files
npm run lint:commit Validate last commit message format
npm run swagger:docs Generate swagger.json from JSDoc annotations
npm run docker:build Build Docker image
npm run docker:up Start Docker container
npm run docker:down Stop and remove Docker volume
AI Commands
/pre-commit Runs linting, tests, and quality checks before committing
/pre-release Runs pre-release validation workflow

Legal

This project is provided for educational and demonstration purposes and may be used in production at your own discretion. All trademarks, service marks, product names, company names, and logos referenced herein are the property of their respective owners and are used solely for identification or illustrative purposes.