{"id":26866362,"url":"https://github.com/nanotaboada/ts-node-samples-express-restful","last_synced_at":"2026-04-02T18:46:13.434Z","repository":{"id":230527119,"uuid":"779527681","full_name":"nanotaboada/ts-node-samples-express-restful","owner":"nanotaboada","description":"🧪 Proof of Concept for a RESTful API made with Node.js 20 (LTS), Express.js 4 in TypeScript","archived":false,"fork":false,"pushed_at":"2024-04-13T02:00:15.000Z","size":598,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-04-13T21:45:35.910Z","etag":null,"topics":["express-js","expressjs","node-js","nodejs","proof-of-concept","rest-api","restful-api","samples","sqlite","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nanotaboada.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-03-30T04:03:29.000Z","updated_at":"2024-04-15T04:11:03.481Z","dependencies_parsed_at":"2024-04-15T04:10:43.255Z","dependency_job_id":null,"html_url":"https://github.com/nanotaboada/ts-node-samples-express-restful","commit_stats":null,"previous_names":["nanotaboada/ts-node-samples-express-restful"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanotaboada%2Fts-node-samples-express-restful","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanotaboada%2Fts-node-samples-express-restful/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanotaboada%2Fts-node-samples-express-restful/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanotaboada%2Fts-node-samples-express-restful/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nanotaboada","download_url":"https://codeload.github.com/nanotaboada/ts-node-samples-express-restful/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246418663,"owners_count":20773935,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["express-js","expressjs","node-js","nodejs","proof-of-concept","rest-api","restful-api","samples","sqlite","typescript"],"created_at":"2025-03-31T04:54:23.022Z","updated_at":"2026-04-02T18:46:13.424Z","avatar_url":"https://github.com/nanotaboada.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🧪 RESTful API with Node.js and Express.js in TypeScript\n\n[![Node.js CI](https://github.com/nanotaboada/ts-node-samples-express-restful/actions/workflows/node-ci.yml/badge.svg)](https://github.com/nanotaboada/ts-node-samples-express-restful/actions/workflows/node-ci.yml)\n[![Node.js CD](https://github.com/nanotaboada/ts-node-samples-express-restful/actions/workflows/node-cd.yml/badge.svg)](https://github.com/nanotaboada/ts-node-samples-express-restful/actions/workflows/node-cd.yml)\n[![CodeQL Advanced](https://github.com/nanotaboada/ts-node-samples-express-restful/actions/workflows/codeql.yml/badge.svg)](https://github.com/nanotaboada/ts-node-samples-express-restful/actions/workflows/codeql.yml)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=nanotaboada_ts-node-samples-express-restful\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=nanotaboada_ts-node-samples-express-restful)\n[![codecov](https://codecov.io/gh/nanotaboada/ts-node-samples-express-restful/branch/master/graph/badge.svg?token=VxKaWl2DfD)](https://codecov.io/gh/nanotaboada/ts-node-samples-express-restful)\n[![CodeFactor](https://www.codefactor.io/repository/github/nanotaboada/ts-node-samples-express-restful/badge)](https://www.codefactor.io/repository/github/nanotaboada/ts-node-samples-express-restful)\n[![License: MIT](https://img.shields.io/badge/License-MIT-3DA639.svg)](https://opensource.org/licenses/MIT)\n![Dependabot](https://img.shields.io/badge/Dependabot-contributing-025E8C?logo=dependabot\u0026logoColor=white\u0026labelColor=181818)\n![GitHub Copilot](https://img.shields.io/badge/GitHub_Copilot-contributing-8662C5?logo=githubcopilot\u0026logoColor=white\u0026labelColor=181818)\n![Claude](https://img.shields.io/badge/Claude-Sonnet_4.6-D97757?logo=claude\u0026logoColor=white\u0026labelColor=181818)\n![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/nanotaboada/ts-node-samples-express-restful?utm_source=oss\u0026utm_medium=github\u0026utm_campaign=nanotaboada%2Fts-node-samples-express-restful\u0026labelColor=181818\u0026link=https%3A%2F%2Fcoderabbit.ai\u0026label=CodeRabbit+Reviews)\n\nProof of Concept for a RESTful API made with [Node.js](https://nodejs.org/) [LTS/Krypton (v24)](https://nodejs.org/en/blog/release/v24.11.1) and [Express.js](https://expressjs.com/) 5 in [TypeScript](https://www.typescriptlang.org/). Manage football player data with SQLite, Sequelize ORM, Swagger documentation, and in-memory caching.\n\n## Table of Contents\n\n- [Features](#features)\n- [Tech Stack](#tech-stack)\n- [Project Structure](#project-structure)\n- [Architecture](#architecture)\n- [Architecture Decisions](#architecture-decisions)\n- [API Reference](#api-reference)\n- [Prerequisites](#prerequisites)\n- [Quick Start](#quick-start)\n- [Testing](#testing)\n- [Containers](#containers)\n- [Releases](#releases)\n- [Environment Variables](#environment-variables)\n- [Command Summary](#command-summary)\n- [Contributing](#contributing)\n- [Legal](#legal)\n\n## Features\n\n- 🏗️ **Modern TypeScript architecture** - Native ESM, strict mode, layered architecture with interface-based contracts\n- 📚 **Interactive API exploration** - Auto-generated OpenAPI docs with Swagger UI and `.rest` HTTP file for VS Code REST Client\n- ⚡ **Performance optimizations** - In-memory caching with node-cache, Sequelize ORM, and efficient SQLite operations\n- 🧪 **Comprehensive integration tests** - Full endpoint coverage with Jest/Supertest and automated reporting to Codecov\n- 📖 **Token-efficient documentation** - Auto-loaded Copilot instructions for AI-assisted development\n- 🐳 **Full containerization** - Multi-stage Docker builds with Docker Compose orchestration\n- 🔄 **Complete CI/CD pipeline** - Automated linting (ESLint/Prettier), testing, Docker publishing, and GitHub releases\n- ⚽ **Football-themed semantic versioning** - Memorable, alphabetical release names using football terminology\n\n## Tech Stack\n\n| Category               | Technology                                                                                                                   |\n|------------------------|------------------------------------------------------------------------------------------------------------------------------|\n| **Runtime**            | [Node.js 24 (LTS/Krypton)](https://github.com/nodejs/node)                                                                  |\n| **Language**           | [TypeScript 5.9](https://github.com/microsoft/TypeScript)                                                                   |\n| **Module System**      | Native ECMAScript Modules (ESM) - uses [tsx](https://github.com/privatenumber/tsx) for execution                           |\n| **Framework**          | [Express.js 5](https://github.com/expressjs/express)                                                                        |\n| **Database**           | [SQLite3](https://github.com/sqlite/sqlite) with [Sequelize ORM](https://github.com/sequelize/sequelize)                   |\n| **Caching**            | [node-cache](https://github.com/node-cache/node-cache)                                                                      |\n| **Documentation**      | [Swagger (OpenAPI 3.0)](https://github.com/swagger-api/swagger-ui)                                                          |\n| **Security**           | [Helmet](https://github.com/helmetjs/helmet), [CORS](https://github.com/expressjs/cors), [express-rate-limit](https://github.com/express-rate-limit/express-rate-limit) |\n| **Testing**            | [Jest 30](https://github.com/jestjs/jest) with [Supertest](https://github.com/ladjs/supertest)                             |\n| **Containerization**   | [Docker](https://github.com/docker) with multi-stage builds                                                                 |\n| **Code Quality**       | [ESLint](https://github.com/eslint/eslint), [Prettier](https://github.com/prettier/prettier), [Commitlint](https://github.com/conventional-changelog/commitlint) |\n| **Dev Tools**          | [tsx](https://github.com/privatenumber/tsx) (TypeScript executor), [nodemon](https://github.com/remy/nodemon)              |\n\n\u003e 💡 **Note:** While the repository name references `ts-node` (the original implementation), the project now uses [tsx](https://github.com/privatenumber/tsx) for faster, cleaner TypeScript execution without experimental flags.\n\n## Project Structure\n\n```text\nsrc/\n├── app.ts              # Express app setup \u0026 middleware configuration\n├── server.ts           # HTTP server initialization \u0026 lifecycle\n├── controllers/        # Request handlers with Swagger annotations\n├── services/           # Business logic + caching layer\n├── database/           # Sequelize DB access (interfaces + implementations)\n├── models/             # Sequelize models (Player)\n├── routes/             # Express Router definitions\n├── docs/               # Swagger configuration \u0026 doc generation\n├── middlewares/        # Custom middleware (rate limiter, validators, Swagger CSP)\n└── utils/              # Pino logger configuration\n\nrest/                   # HTTP request files for VS Code REST Client\ntests/                  # Integration tests with supertest\nscripts/                # Docker entrypoint \u0026 healthcheck scripts\nstorage/                # Pre-seeded SQLite database\n```\n\n## Architecture\n\nLayered architecture with dependency injection via constructors and interface-based contracts.\n\n```mermaid\n%%{init: {\n  \"theme\": \"default\",\n  \"themeVariables\": {\n    \"fontFamily\": \"Fira Code, Consolas, monospace\",\n    \"textColor\": \"#555\",\n    \"lineColor\": \"#555\",\n    \"lineWidth\": 2,\n    \"clusterBkg\": \"#f5f5f5\",\n    \"clusterBorder\": \"#999\"\n  }\n}}%%\n\ngraph RL\n\n    tests[tests]\n\n    subgraph Layer 1[\" \"]\n        server[server]\n        app[app]\n    end\n\n    subgraph Layer 2[\" \"]\n        routes[routes]\n        controllers[controllers]\n        Express[Express]\n    end\n\n    subgraph Layer 3[\" \"]\n        services[services]\n        nodeCache[node-cache]\n    end\n\n    subgraph Layer 4[\" \"]\n        database[database]\n        Sequelize[Sequelize]\n    end\n\n    models[models]\n\n    %% Dependencies\n\n    app --\u003e server\n    routes --\u003e app\n    controllers --\u003e routes\n    services --\u003e controllers\n    database --\u003e services\n\n    Express --\u003e routes\n    nodeCache --\u003e services\n    Sequelize --\u003e database\n\n    Express --\u003e app\n    Express -.-\u003e controllers\n    Sequelize -.-\u003e models\n\n    app -.-\u003e tests\n\n    models -.-\u003e database\n    models -.-\u003e services\n    models -.-\u003e controllers\n\n    controllers --\u003e app\n    services --\u003e app\n    database --\u003e app\n\n    %% Styling\n    classDef core fill:#b3d9ff,stroke:#6db1ff,stroke-width:2px,color:#555,font-family:monospace;\n    classDef deps fill:#ffcccc,stroke:#ff8f8f,stroke-width:2px,color:#555,font-family:monospace;\n    classDef test fill:#ccffcc,stroke:#53c45e,stroke-width:2px,color:#555,font-family:monospace;\n\n    class server,app,routes,controllers,services,database,models core\n    class Express,Sequelize,nodeCache deps\n    class tests test\n```\n\n### Arrow Semantics\n\nArrows follow the wiring direction: `A --\u003e B` means A is provided to B. Solid arrows (`--\u003e`) represent active dependencies — modules explicitly wired in `app` and invoked at runtime. Dotted arrows (`-.-\u003e`) represent structural dependencies — the consumer references types or interfaces without invoking runtime behavior.\n\n### Composition Root Pattern\n\n`app` is the composition root: it instantiates all dependencies, configures Express middleware, and registers all routes. `server` is separate and owns only the HTTP lifecycle (port binding, graceful shutdown) — a conventional split in Express projects.\n\n### Layered Architecture\n\nFour layers: Initialization (`server`, `app`), HTTP (`routes`, `controllers`), Business (`services`), and Data (`database`).\n\n`models` is a cross-cutting type concern — shared types and Sequelize model definitions consumed across multiple layers, with no business logic of its own.\n\n### Color Coding\n\nBlue = core application packages, red = third-party frameworks, green = tests.\n\n*Simplified, conceptual project structure and main application flow. Not all dependencies are shown.*\n\n## Architecture Decisions\n\nSignificant architectural choices — why they were made, what tradeoffs they carry — are documented as Architecture Decision Records (ADRs) in [`docs/adr/`](docs/adr/).\n\n| ADR | Decision |\n|-----|----------|\n| [001](docs/adr/001-interface-based-architecture.md) | Interface-based architecture with constructor injection |\n| [002](docs/adr/002-uuid-primary-key-and-squad-number-mutation-key.md) | UUID as primary key, squadNumber as mutation key |\n| [003](docs/adr/003-use-native-esm.md) | Native ESM instead of CommonJS |\n| [004](docs/adr/004-use-express-5.md) | Express 5 |\n| [005](docs/adr/005-use-sqlite-sequelize.md) | SQLite with Sequelize ORM |\n| [006](docs/adr/006-integration-first-testing-strategy.md) | Integration-first testing (real DB, no mocks) |\n| [007](docs/adr/007-node-cache-strategy.md) | node-cache with 1-hour TTL |\n| [008](docs/adr/008-use-pino-structured-logging.md) | Pino for structured logging |\n| [009](docs/adr/009-docker-and-compose-strategy.md) | Multi-stage Docker builds + Compose |\n| [010](docs/adr/010-use-tsx-over-ts-node.md) | tsx instead of ts-node |\n| [011](docs/adr/011-football-semantic-versioning.md) | Football-themed semantic versioning |\n\n## API Reference\n\nInteractive API documentation is available via Swagger UI at `http://localhost:9000/swagger/` when the server is running.\n\n**Quick Reference:**\n\n- `GET /players` - List all players\n- `GET /players/:id` - Get player by ID\n- `GET /players/squadNumber/:squadNumber` - Get player by squad number\n- `POST /players` - Create new player\n- `PUT /players/:id` - Update player\n- `DELETE /players/:id` - Remove player\n- `GET /health` - Health check\n\nFor complete endpoint documentation with request/response schemas, explore the [interactive Swagger UI](http://localhost:9000/swagger/). You can also access the OpenAPI JSON specification at `http://localhost:9000/swagger.json`.\n\nAlternatively, use [`rest/players.rest`](rest/players.rest) with the [REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) extension for VS Code to send requests directly from the editor.\n\n## Prerequisites\n\nBefore you begin, ensure you have the following installed:\n\n- Node.js (see `.nvmrc` for required version)\n- npm (comes with Node.js)\n- [direnv](https://direnv.net/) (optional, but recommended — auto-loads the correct Node.js version via `.nvmrc` on directory entry)\n- Docker and Docker Compose (optional, for containerized setup)\n\n## Quick Start\n\n### Clone the repository\n\n```bash\ngit clone https://github.com/nanotaboada/ts-node-samples-express-restful.git\ncd ts-node-samples-express-restful\n```\n\n### Install dependencies\n\n```bash\nnpm install\n```\n\n### Start the development server\n\n```bash\nnpm run dev\n```\n\nThe server will start on `http://localhost:9000` with the following output:\n\n```console\n\u003e ts-node-samples-express-restful@1.0.0 dev\n\u003e nodemon\n\n[nodemon] to restart at any time, enter `rs`\n[nodemon] watching path(s): src/**/*\n[nodemon] watching extensions: ts\n[nodemon] starting `tsx ./src/server.ts`\n🚀 Running at http://localhost:9000\n```\n\n### Access the application\n\n- API: `http://localhost:9000`\n- Swagger Documentation: `http://localhost:9000/swagger/`\n- Health Check: `http://localhost:9000/health`\n\n## Testing\n\nRun the test suite with Jest:\n\n```bash\n# Run all tests\nnpm test\n\n# Run tests with coverage report\nnpm run coverage\n\n# Run linter\nnpm run lint\n\n# Validate commit message format\nnpm run lint:commit\n```\n\nTests are located in the `tests/` directory and use Supertest for integration testing. Coverage reports are generated for controllers, services, and routes only.\n\n## Containers\n\nThis project includes full Docker support with multi-stage builds and Docker Compose for easy deployment.\n\n### Build the Docker image\n\n```bash\nnpm run docker:build\n# or\ndocker compose build\n```\n\n### Start the application\n\n```bash\nnpm run docker:up\n# or\ndocker compose up\n```\n\n\u003e 💡 **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.\n\n### Stop the application\n\n```bash\nnpm run docker:down\n# or\ndocker compose down\n```\n\n### Reset the database\n\nTo remove the volume and reinitialize the database from the built-in seed file:\n\n```bash\ndocker compose down -v\n```\n\nThe containerized application runs on port 9000 and includes health checks that monitor the `/health` endpoint every 30 seconds.\n\n## Releases\n\nThis project uses football terminology as release names ⚽\n\n### Release Naming Convention\n\nReleases follow the pattern: `v{SEMVER}-{TERM}` (e.g., `v1.0.0-assist`)\n\n- **Semantic Version**: Standard versioning (MAJOR.MINOR.PATCH)\n- **Term Name**: Alphabetically ordered codename from the [football terminology list](CHANGELOG.md#football-terminology-names-️)\n\n### Create a Release\n\nTo create a new release, follow this workflow:\n\n#### 1. Create a Release Branch\n\nBranch protection prevents direct pushes to `master`, so all release prep goes through a PR:\n\n```bash\ngit checkout master \u0026\u0026 git pull\ngit checkout -b release/vX.Y.Z-term\n```\n\n#### 2. Update CHANGELOG.md\n\nMove items from `[Unreleased]` to a new release section in [CHANGELOG.md](CHANGELOG.md), then commit and push the branch:\n\n```bash\n# Move items from [Unreleased] to new release section\n# Example: [2.0.0 - corner] - 2026-03-29\ngit add CHANGELOG.md\ngit commit -m \"chore(release): vX.Y.Z-term\"\ngit push origin release/vX.Y.Z-term\n```\n\n#### 3. Merge the Release PR\n\nOpen a pull request from `release/vX.Y.Z-term` into `master` and merge it. The tag must be created **after** the merge so it points to the correct commit on `master`.\n\n#### 4. Create and Push Tag\n\nAfter the PR is merged, pull `master` and create the annotated tag:\n\n```bash\ngit checkout master \u0026\u0026 git pull\ngit tag -a vX.Y.Z-term -m \"Release X.Y.Z - Term\"\ngit push origin vX.Y.Z-term\n```\n\nExample:\n\n```bash\ngit tag -a v2.0.0-corner -m \"Release 2.0.0 - Corner\"\ngit push origin v2.0.0-corner\n```\n\n#### 5. Automated CD Workflow\n\nPushing the tag triggers the CD pipeline which automatically:\n\n1. Builds and tests the project\n2. Publishes Docker images to GitHub Container Registry\n3. Creates a GitHub Release with auto-generated changelog from commits\n\n#### Pre-Release Checklist\n\n- [ ] Release branch created from `master`\n- [ ] `CHANGELOG.md` updated with release notes\n- [ ] Changes committed and pushed on the release branch\n- [ ] Release PR merged into `master`\n- [ ] Tag created with correct format: `vX.Y.Z-term`\n- [ ] Term is valid (A-Z from the [football terminology list](CHANGELOG.md#football-terminology-names-️))\n- [ ] Tag pushed to trigger CD workflow\n\n### Pull Docker Images\n\nEach release publishes three Docker tags:\n\n```bash\n# By semantic version (recommended for production)\ndocker pull ghcr.io/nanotaboada/ts-node-samples-express-restful:1.0.0\n\n# By term name (memorable, useful for staging)\ndocker pull ghcr.io/nanotaboada/ts-node-samples-express-restful:assist\n\n# Latest (development/testing only)\ndocker pull ghcr.io/nanotaboada/ts-node-samples-express-restful:latest\n```\n\n## Environment Variables\n\nCreate a `.env` file in the root directory to customize configuration:\n\n```env\n# Server port (default: 9000)\nPORT=9000\n\n# Database storage path (default: storage/players-sqlite3.db)\n# In Docker: /storage/players-sqlite3.db\nSTORAGE_PATH=storage/players-sqlite3.db\n\n# Rate limiting (all optional — defaults shown)\nRATE_LIMIT_ENABLED=true                 # Set to 'false' to disable rate limiting entirely\nRATE_LIMIT_WINDOW_MS=60000              # Time window in milliseconds (default: 1 minute)\nRATE_LIMIT_MAX_GENERAL=100             # Max requests per window for all routes\nRATE_LIMIT_MAX_STRICT=20               # Max requests per window for POST/PUT/DELETE\n```\n\n## Command Summary\n\n| Script                 | Description                                       |\n|------------------------|---------------------------------------------------|\n| `npm run dev`          | Start development server with hot reload          |\n| `npm start`            | Run compiled application from `dist/`             |\n| `npm run build`        | Compile TypeScript to JavaScript                  |\n| `npm test`             | Run Jest tests with --detectOpenHandles flag      |\n| `npm run coverage`     | Generate test coverage report                     |\n| `npm run lint`         | Run ESLint on all files                           |\n| `npm run lint:commit`  | Validate last commit message format               |\n| `npm run swagger:docs` | Generate swagger.json from JSDoc annotations      |\n| `npm run docker:build` | Build Docker image                                |\n| `npm run docker:up`    | Start Docker container                            |\n| `npm run docker:down`  | Stop and remove Docker volume                     |\n\n## Contributing\n\nContributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the code of conduct and the process for submitting pull requests.\n\nKey guidelines:\n\n- Follow [Conventional Commits](https://www.conventionalcommits.org/) for commit messages\n- Ensure all tests pass (`npm test`)\n- Run linter before committing (`npm run lint`)\n- Keep changes small and focused\n\n## Legal\n\nThis 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.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnanotaboada%2Fts-node-samples-express-restful","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnanotaboada%2Fts-node-samples-express-restful","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnanotaboada%2Fts-node-samples-express-restful/lists"}