{"id":29861346,"url":"https://github.com/hoghweed/apibench","last_synced_at":"2026-05-03T11:34:04.146Z","repository":{"id":306284178,"uuid":"1024534754","full_name":"hoghweed/apibench","owner":"hoghweed","description":"A simple sample api application","archived":false,"fork":false,"pushed_at":"2025-07-24T16:19:03.000Z","size":793,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-09T07:06:12.791Z","etag":null,"topics":["fastify","nodejs","typescript","vitest"],"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/hoghweed.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,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-22T21:20:22.000Z","updated_at":"2025-07-24T16:19:06.000Z","dependencies_parsed_at":"2025-07-24T20:51:20.321Z","dependency_job_id":"1bd894a7-af60-4063-8ea3-aa912549e239","html_url":"https://github.com/hoghweed/apibench","commit_stats":null,"previous_names":["hoghweed/apibench"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hoghweed/apibench","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoghweed%2Fapibench","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoghweed%2Fapibench/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoghweed%2Fapibench/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoghweed%2Fapibench/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hoghweed","download_url":"https://codeload.github.com/hoghweed/apibench/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoghweed%2Fapibench/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32567417,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T06:36:36.687Z","status":"ssl_error","status_checked_at":"2026-05-03T06:36:09.306Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["fastify","nodejs","typescript","vitest"],"created_at":"2025-07-30T05:01:14.839Z","updated_at":"2026-05-03T11:34:04.130Z","avatar_url":"https://github.com/hoghweed.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# apibench\n\nA simple, modern API project using Fastify, MongoDB, TypeScript, and robust structure ideal for benchmarking, learning, or prototyping.\n\n---\n\n## Table of Contents\n- [apibench](#apibench)\n  - [Table of Contents](#table-of-contents)\n  - [Project Overview](#project-overview)\n  - [Architecture](#architecture)\n  - [Key Features and Capabilities](#key-features-and-capabilities)\n  - [Project Structure](#project-structure)\n  - [Environment Variables](#environment-variables)\n  - [Fastify Plugins](#fastify-plugins)\n  - [API Routes](#api-routes)\n    - [**POST /api/users**](#post-apiusers)\n    - [**GET /api/users?created=asc|desc**](#get-apiuserscreatedascdesc)\n    - [**OpenAPI Docs**](#openapi-docs)\n    - [**Health Endpoints**](#health-endpoints)\n  - [Development Infrastructure](#development-infrastructure)\n  - [Scripts and Commands](#scripts-and-commands)\n  - [Getting Started](#getting-started)\n  - [Testing Your API with `/reference`](#testing-your-api-with-reference)\n  - [Screenshots](#screenshots)\n  - [License](#license)\n  - [Contributors](#contributors)\n\n---\n\n## Project Overview\n\n**apibench** is a sample RESTful API designed as a reference or starting point for secure and scalable API backends. It demonstrates clean architecture, password hashing, validation, error handling, plugin isolation, OpenAPI integration, and containerized infrastructure. It is suitable for both rapid prototyping and benchmarking.\n\n---\n\n## Architecture\n\n- Built with **Fastify**, known for its speed and powerful plugin system.\n- Models, validations, and response types are defined with **TypeScript** and **zod**.\n- Uses **MongoDB** as the primary data store, managed via the official `mongodb` Node.js client.\n- Infrastructure runs in containers using **Docker Compose**, with optional local GUI for database management.\n- All configuration is environment-driven and supports best practices for cloud and local workflows.\n\n**Good practices:**\n- Encapsulation: Business logic, validation, and persistence are modularized using Fastify plugins.\n- Extensibility: Adding new routes or swapping backend resources (like a different DB) can be done with minimal changes.\n- Observability: Health checks and logging are built in.\n\n---\n\n## Key Features and Capabilities\n\n- User registration, password salting \u0026 hashing, and user listing.\n- Slugify logic for usernames, with support for auto-generation from name.\n- Duplicate user protection.\n- Exposes OpenAPI/Swagger docs at `/reference` using plugin integration.\n- Health probes for Kubernetes/Docker (`/healthz`, `/liveness`).\n- Database connection pooling and process shutdown hooks.\n- All configuration can be customized via `.env`.\n- Clear plugin boundaries for database, error handling, validation, config, and Swagger.\n\n---\n\n## Project Structure\n\n```\napibench/\n├── .env                      # Main environment config\n├── compose.yaml              # Docker Compose infrastructure setup\n├── src/\n│   ├── app.ts                # Main Fastify app creation and plugin loading\n│   ├── server.ts             # Application lifecycle and server startup\n│   ├── env.ts                # Loads env vars\n│   ├── plugins/              # Fastify plugin modules (db, configuration, error, swagger)\n│   ├── routes/               # API route modules (users-create, users-get)\n│   ├── errors/               # Application-specific error classes\n│   └── types.ts              # Zod and TypeScript models/types\n├── package.json\n└── ... (see project tree for remaining files)\n```\n\n---\n\n## Environment Variables\n\nDefined in `.env` (sample values shown):\n\n| Variable             | Description                         | Example                         |\n|----------------------|-------------------------------------|---------------------------------|\n| NODE_ENV             | Node environment                    | development                    |\n| APPLICATION_NAME     | Service/application identifier      | apibench                       |\n| APPLICATION_PORT     | Port for Fastify server             | 4111                            |\n| CLOSE_GRACE_DELAY    | Graceful shutdown delay (ms)        | 1000                            |\n| DB_URL               | MongoDB connection string           | mongodb://apibench:apibench@localhost:27018 |\n| DB_NAME              | MongoDB database name               | apibench                        |\n| LOG_LEVEL            | Fastify log level (debug, info...)  | debug, info, warn, error, silent|\n\n---\n\n## Fastify Plugins\n\nThe application benefits from Fastify's plugin architecture for maintainability and encapsulation. Major plugins in use:\n\n- **@fastify/autoload**: Automatically loads plugins/routes from directories.\n- **arecibo**: Health and liveness checking plugin.\n- **fastify-type-provider-zod**: Integrates Zod with Fastify for runtime validation and OpenAPI generation.\n- **@scalar/fastify-api-reference**: Serves OpenAPI documentation at `/reference`.\n- **@fastify/one-line-logger**: Conditional, for clean log formatting (enabled based on LOG_LEVEL).\n- **Custom plugins** in `/src/plugins/`:\n  - `db.ts`: MongoDB client with graceful shutdown and collection registry.\n  - `configuration.ts`: Loads and attaches configuration to Fastify instance.\n  - `error.ts`: Custom error serialization and handling logic.\n  - `swagger.ts`: Sets up aggregation of OpenAPI doc routes and UI.\n\n---\n\n## API Routes\n\nAll API endpoints are prefixed with `/api`.\n\n### **POST /api/users**\n- **Purpose:** Create a new user account.\n- **Body:**  \n  - `name: string` (min 5 chars)\n  - `email: string` (valid email)\n  - `password: string` (min 8 chars; stored salted/hashed)\n  - `username: string` (optional; slugified, auto-generated if missing)\n  - `isActive: boolean` (optional, default: true)\n- **Behavior:**\n  - Slugifies username or generates from name if missing.\n  - Hashes password using bcrypt.\n  - Checks for username uniqueness; returns 409 on duplicate.\n  - Timestamps for created/updated set by server.\n- **Success:** `201 Created` with user (no password field, includes string id)\n- **Error:** `409 Conflict` (duplicate username), `400` for validation errors\n\n### **GET /api/users?created=asc|desc**\n- **Purpose:** List all users, sorted by creation time.\n- **Query:**  \n  - `created: 'asc' | 'desc'` (sort direction, required)\n- **Response:**  \n  - Array of users, each omitting password.\n  - Ordered by time as specified.\n- **Error:**\n  - `400` for query or server issues.\n\n### **OpenAPI Docs**\n- **GET /reference**\n- OpenAPI schema and live UI generated from code/schema.\n\n### **Health Endpoints**\n- **GET /healthz** (readiness)  \n- **GET /liveness** (liveness)\n\n---\n\n## Development Infrastructure\n\nThe repository includes a Docker Compose stack for local dev and CI:\n\n- **ab-mongo**: MongoDB container (with auth, persistent volume, healthcheck)\n- **ab-mongo-express**: Web GUI for MongoDB admin at [http://localhost:8082](http://localhost:8082) (`admin`/`password` for basic auth)\n- **ab-wait-for-dependencies**: Waits for DB and GUI services to be healthy before proceeding\n\nAll services are networked under `ab-network` and data persists in the `./data` directory.\n\n---\n\n## Scripts and Commands\n\nKey npm/pnpm scripts (`package.json`):\n\n| Script               | Description                                                          |\n|----------------------|----------------------------------------------------------------------|\n| `dev`                | Start Fastify in dev mode, reload on changes, loads `.env`           |\n| `build`              | Build TypeScript project into `/dist`                                |\n| `start`              | Run dev infra and then application (uses Docker Compose dependencies)|\n| `test`               | Run tests with Vitest (auto-loads `.env`)                            |\n| `test:coverage`      | Run tests and collect code coverage                                  |\n| `lint`               | Run Biome for linting                                                |\n| `format`             | Run Biome for formatting                                             |\n| `run:infra`          | Launch dev infrastructure via Docker Compose                         |\n| `run:infra:stop`     | Stop dev infrastructure containers                                   |\n\n---\n\n## Getting Started\n\n1. **Install dependencies:**  \n   ```sh\n   pnpm boostrap\n   ```\n2. **Setup environment:**  \n   Edit `.env` as needed.\n3. **Start app in development:**  \n   ```sh\n   pnpm start\n   ```\n   this will start automatically the infrastructure as well\n\n4. **Explore API and docs:**  \n   - API: [http://localhost:4111/api/users](http://localhost:4111/api/users)\n   - Docs: [http://localhost:4111/reference](http://localhost:4111/reference)\n   - MongoDB GUI: [http://localhost:8082](http://localhost:8082) (`admin`/`password`)\n\n---\n\n## Testing Your API with `/reference`\n\nThe application automatically generates and serves full OpenAPI (Swagger) documentation at the `/reference` endpoint. This interactive documentation allows you to:\n\n- Explore all available API routes and their schemas.\n- Try API calls directly from your browser using the \"Try it out\" feature.\n- View request/response formats, possible status codes, and sample payloads.\n\n**To use:**\n1. Start the server as described above.\n2. Open [http://localhost:4111/reference](http://localhost:4111/reference) in your browser.\n3. Expand endpoints, fill in example data, and test your API live.\n\nThis is a fast way to verify the API works as expected and to share API exploration with your team.\n\n---\n\n## Screenshots\n\n\u003e _Add your screenshots here!_\n\u003e\n\u003e **API Reference Example:**  \n\u003e ![API Reference UI](screenshots/api-reference.png)\n\u003e\n\u003e **MongoDB GUI Example:**  \n\u003e ![MongoDB GUI](screenshots/mongo-gui.png)\n\u003e\n\u003e **User Creation Request/Response:**  \n\u003e ![User Creation](screenshots/create-user.png)\n\u003e\n\u003e _To add your own screenshots, simply save images in the `screenshots/` directory and update these markdown paths._\n\n---\n\n## License\n\nMIT © Manuel S. Martone\n\n---\n\n## Contributors\n\n- [Manuel S. Martone](mailto:manuel.martone@gmail.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoghweed%2Fapibench","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhoghweed%2Fapibench","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoghweed%2Fapibench/lists"}