{"id":28092757,"url":"https://github.com/gubiar/real-world-fastify","last_synced_at":"2025-08-12T16:42:55.941Z","repository":{"id":291594777,"uuid":"971376814","full_name":"Gubiar/real-world-fastify","owner":"Gubiar","description":"Real-World Fastify Boilerplate","archived":false,"fork":false,"pushed_at":"2025-05-06T14:27:51.000Z","size":341,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-13T13:51:21.111Z","etag":null,"topics":["docker","docker-compose","fastify","postgresql","prisma","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Gubiar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-04-23T12:35:55.000Z","updated_at":"2025-05-06T14:27:54.000Z","dependencies_parsed_at":"2025-05-05T15:38:27.491Z","dependency_job_id":null,"html_url":"https://github.com/Gubiar/real-world-fastify","commit_stats":null,"previous_names":["gubiar/real-world-fastify"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Gubiar/real-world-fastify","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gubiar%2Freal-world-fastify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gubiar%2Freal-world-fastify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gubiar%2Freal-world-fastify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gubiar%2Freal-world-fastify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Gubiar","download_url":"https://codeload.github.com/Gubiar/real-world-fastify/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gubiar%2Freal-world-fastify/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270099688,"owners_count":24527037,"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","status":"online","status_checked_at":"2025-08-12T02:00:09.011Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["docker","docker-compose","fastify","postgresql","prisma","typescript"],"created_at":"2025-05-13T13:40:57.851Z","updated_at":"2025-08-12T16:42:55.886Z","avatar_url":"https://github.com/Gubiar.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Real-World Fastify Boilerplate\n\nA production-ready Fastify boilerplate with TypeScript, Prisma, JWT authentication, and comprehensive testing. This project follows best practices for building secure, maintainable, and scalable REST APIs.\n\n## Features\n\n- **Fastify Web Framework**: High-performance Node.js framework\n- **TypeScript**: With strict type checking and proper error handling\n- **Prisma ORM**: Type-safe database access with PostgreSQL\n- **JWT Authentication**: Secure authentication with @fastify/jwt\n- **Request Validation**: Using TypeBox for runtime validation\n- **Swagger Documentation**: Interactive API documentation\n- **Rate Limiting**: Protection against brute force attacks\n- **Security Headers**: Using Helmet and proper CORS configuration\n- **Error Handling**: Global error handler with proper responses\n- **Testing**: Jest setup with example tests\n- **Logging**: Advanced Pino logging with redaction\n- **Code Structure**: Clear modular architecture\n- **ESLint**: Modern linting setup\n\n## Project Structure\n\n```\n├── src/\n│   ├── modules/           # Feature modules\n│   │   ├── auth/          # Authentication module\n│   │   │   ├── auth.controller.ts\n│   │   │   ├── auth.route.ts\n│   │   │   ├── auth.schema.ts\n│   │   │   └── auth.service.ts\n│   │   ├── users/         # User management\n│   │   │   └── user.service.ts\n│   │   └── base.route.ts  # Base router class\n│   ├── plugins/           # Fastify plugins\n│   │   ├── jwt.ts         # JWT authentication\n│   │   ├── errorHandler.ts # Global error handler\n│   │   └── rateLimit.ts   # Rate limiting\n│   ├── utils/             # Utility functions\n│   │   ├── httpStatusCodes.ts\n│   │   ├── logger.ts\n│   │   ├── prisma.ts      # Prisma client\n│   │   └── response.ts    # Response helpers\n│   └── app.ts             # Application entry point\n├── prisma/\n│   └── schema.prisma      # Database schema\n├── test/                  # Tests\n│   ├── auth/              # Auth tests\n│   │   └── auth.test.ts\n│   └── setup.ts           # Test setup\n├── eslint.config.js       # ESLint configuration\n├── jest.config.js         # Jest configuration\n├── tsconfig.json          # TypeScript configuration\n├── sample.env             # Environment variables example\n└── package.json           # Dependencies and scripts\n```\n\n## Getting Started\n\n### Prerequisites\n\n- Node.js 18+ (LTS recommended)\n- pnpm/npm package manager\n- PostgreSQL 13+\n\n### Installation\n\n1. Clone the repository:\n\n```bash\ngit clone https://github.com/Gubiar/real-world-fastify.git\ncd real-world-fastify\n```\n\n2. Install dependencies:\n\n```bash\npnpm install\n# or\nnpm install\n```\n\n3. Set up environment variables:\n\n```bash\ncp sample.env .env\n```\n\nEdit the `.env` file with your configuration:\n\n```\n# Server configuration\nPORT=3000\nHOST=\"0.0.0.0\"\nNODE_ENV=\"development\"\n\n# Database\nDATABASE_URL=\"postgresql://USER:PASSWORD@localhost:5432/fastify_db?schema=public\"\n\n# Authentication\nJWT_SECRET=\"your-super-secret-key\"\nJWT_EXPIRES_IN=\"1d\"\n\n# CORS\nCORS_ORIGIN=\"http://localhost:3000\"\n\n# Logging\nLOG_LEVEL=\"info\"\n```\n\n4. Set up the database:\n\n```bash\n# Create database migrations\npnpm db:migrate\n# or\nnpm run db:migrate\n\n# Optional: Seed the database\npnpm db:seed\n# or\nnpm run db:seed\n```\n\n### Running the Application\n\n#### Development Mode\n\n```bash\npnpm dev\n# or\nnpm run dev\n```\n\nThis starts the server with hot reloading at http://localhost:3000.\n\n#### Production Mode\n\n```bash\n# Build the application\npnpm build\n# or\nnpm run build\n\n# Start the production server\npnpm start\n# or\nnpm start\n```\n\n### API Documentation\n\nSwagger documentation is available at http://localhost:3000/docs when the server is running.\n\n## Creating New Routes\n\nThe project follows a modular architecture where each feature has its own module. To create new routes:\n\n1. **Create a new module directory** under `src/modules/your-feature/`.\n\n2. **Create the schema file** with TypeBox schemas for request/response:\n\n```typescript\n// src/modules/your-feature/feature.schema.ts\nimport { Type, Static } from \"@sinclair/typebox\";\n\nexport const FeatureInput = Type.Object({\n  property: Type.String(),\n  // Define your properties\n});\n\nexport type FeatureInputType = Static\u003ctypeof FeatureInput\u003e;\n\nexport const FeatureResponse = Type.Object({\n  success: Type.Boolean(),\n  data: Type.Object({\n    // Define response properties\n  }),\n});\n```\n\n3. **Create a service** to handle business logic:\n\n```typescript\n// src/modules/your-feature/feature.service.ts\nimport { FastifyInstance } from \"fastify\";\n\nexport async function someMethod(server: FastifyInstance) {\n  // Implement your business logic\n  return await server.prisma.someModel.findMany();\n}\n```\n\n4. **Create a controller** to handle requests:\n\n```typescript\n// src/modules/your-feature/feature.controller.ts\nimport { FastifyReply, FastifyRequest } from \"fastify\";\nimport { FeatureInputType } from \"./feature.schema\";\nimport { someMethod } from \"./feature.service\";\nimport { success, error } from \"../../utils/response\";\nimport { HttpStatus } from \"../../utils/httpStatusCodes\";\n\nexport async function handleRequest(request: FastifyRequest\u003c{ Body: FeatureInputType }\u003e, reply: FastifyReply) {\n  try {\n    const result = await someMethod(request.server);\n    return success(reply, result);\n  } catch (err) {\n    return error(reply, \"Error message\", HttpStatus.INTERNAL_ERROR);\n  }\n}\n```\n\n5. **Create a router** extending BaseRouter:\n\n```typescript\n// src/modules/your-feature/feature.route.ts\nimport { FastifyInstance } from \"fastify\";\nimport { TypeBoxTypeProvider } from \"@fastify/type-provider-typebox\";\nimport { handleRequest } from \"./feature.controller\";\nimport { FeatureInput, FeatureResponse } from \"./feature.schema\";\n\nexport function registerFeatureRoutes(server: FastifyInstance, prefix: string): void {\n  server.register(\n    async (instance) =\u003e {\n      const fastifyTypebox = instance.withTypeProvider\u003cTypeBoxTypeProvider\u003e();\n\n      fastifyTypebox.post(\n        \"/endpoint\",\n        {\n          schema: {\n            body: FeatureInput,\n            response: {\n              200: FeatureResponse,\n            },\n            description: \"Endpoint description\",\n            tags: [\"feature-tag\"],\n          },\n        },\n        handleRequest\n      );\n\n      // Add more routes as needed\n    },\n    { prefix }\n  );\n}\n```\n\n6. **Register your router** in `app.ts`:\n\n```typescript\n// In src/app.ts\nimport { registerFeatureRoutes } from \"./modules/your-feature/feature.route\";\n\n// Register routes\nregisterFeatureRoutes(server, \"/api/your-feature\");\n```\n\n## Testing\n\nThe project uses Jest for testing. Tests are located in the `test/` directory.\n\n### Running Tests\n\n```bash\n# Run all tests\npnpm test\n# or\nnpm test\n\n# Run tests with coverage\npnpm test:coverage\n# or\nnpm run test:coverage\n\n# Run tests in watch mode during development\npnpm test:watch\n# or\nnpm run test:watch\n```\n\n### Writing Tests\n\n1. Create a new test file in the appropriate subdirectory under `test/`.\n2. Follow the example in `test/auth/auth.test.ts`.\n3. Use `app.inject()` for HTTP testing without starting a server.\n\nExample:\n\n```typescript\nimport { test, expect, describe, beforeAll, afterAll } from \"@jest/globals\";\nimport { FastifyInstance } from \"fastify\";\nimport fastify from \"fastify\";\nimport { registerFeatureRoutes } from \"../../src/modules/your-feature/feature.route\";\nimport prismaPlugin from \"../../src/plugins/prisma\";\nimport jwtPlugin from \"../../src/plugins/jwt\";\n\ndescribe(\"Your Feature\", () =\u003e {\n  let app: FastifyInstance;\n\n  beforeAll(async () =\u003e {\n    app = fastify();\n\n    // Register plugins\n    await app.register(prismaPlugin);\n    await app.register(jwtPlugin);\n\n    // Register routes\n    registerFeatureRoutes(app, \"/api/your-feature\");\n\n    await app.ready();\n  });\n\n  afterAll(async () =\u003e {\n    await app.close();\n  });\n\n  test(\"should perform an action\", async () =\u003e {\n    const response = await app.inject({\n      method: \"POST\",\n      url: \"/api/your-feature/endpoint\",\n      payload: {\n        // Test data\n      },\n    });\n\n    expect(response.statusCode).toBe(200);\n    // More assertions\n  });\n});\n```\n\n## Security\n\nThis boilerplate includes several security features:\n\n- **Password Hashing**: Using bcrypt with proper salt rounds\n- **JWT Authentication**: Secure token-based authentication\n- **Rate Limiting**: Protect against brute force attacks\n- **Helmet**: HTTP security headers\n- **CORS**: Configured cross-origin resource sharing\n- **Validation**: Request validation to prevent injections\n- **Data Sanitization**: User data is sanitized before responses\n\n## Deployment\n\nFor production deployment:\n\n1. Set the `NODE_ENV` environment variable to `production`.\n2. Ensure all sensitive environment variables are securely set.\n3. Use a process manager like PM2 or run in a Docker container.\n4. Set up a reverse proxy (Nginx, Apache) for production use.\n\n## Deployment with Docker\n\nThis project includes Docker setup for easy deployment. Docker handles all dependencies, database setup, and running the application in an isolated environment.\n\n## Docker Prerequisites\n\n- [Docker](https://docs.docker.com/get-docker/)\n- [Docker Compose](https://docs.docker.com/compose/install/)\n\n## Deploying with Docker\n\nYou can use the included deployment script:\n\n```bash\n# Make the script executable\nchmod +x deploy.sh\n\n# Deploy with default settings\n./deploy.sh\n\n# Build images before starting\n./deploy.sh --build\n\n# Force recreation of containers\n./deploy.sh --recreate\n\n# Follow logs after starting\n./deploy.sh --logs\n\n# Stop and remove containers\n./deploy.sh --down\n```\n\nOr manually with Docker Compose:\n\n```bash\n# Build and start in detached mode\ndocker-compose up -d --build\n\n# View logs\ndocker-compose logs -f\n\n# Stop containers\ndocker-compose down\n```\n\n## Docker Configuration\n\nThe Docker setup includes:\n\n- **Multi-stage build**: optimized for smaller production images\n- **PostgreSQL database**: pre-configured and ready to use\n- **Automatic migrations**: runs Prisma migrations on startup\n- **Environment variables**: configurable via docker-compose.yml\n- **Volume persistence**: database data persists between restarts\n- **Security**: runs as non-root user\n\n## Production Deployment Considerations\n\nFor production deployment:\n\n1. Set a strong JWT_SECRET environment variable\n2. Use a proper domain in CORS_ORIGIN\n3. Consider using Docker Swarm or Kubernetes for clustering\n4. Set up a reverse proxy (like Nginx) for SSL termination\n5. Use a dedicated database service instead of the Docker container for important data\n\n## Deployment with Docker in WSL\n\nFor Windows users using WSL (Windows Subsystem for Linux), we provide a specialized deployment script with optimizations for WSL environments.\n\n```bash\n# Make the script executable\nchmod +x wsl-deploy.sh\n\n# Deploy with extended timeouts and optimizations for WSL\n./wsl-deploy.sh --pull --build\n\n# View logs\n./wsl-deploy.sh --logs\n```\n\n### WSL Performance Tips\n\nWhen running Docker in WSL:\n\n1. **Store project files in the WSL filesystem** (not `/mnt/c/...`) for better performance\n2. **Use WSL 2** rather than WSL 1 for improved virtualization\n3. **Install Docker Desktop for Windows** with WSL 2 integration\n4. **Increase Docker timeouts** for slower network connections\n\nFor more troubleshooting help, see [TROUBLESHOOTING.md](TROUBLESHOOTING.md).\n\n## Contributing\n\n1. Fork the repository\n2. Create your feature branch: `git checkout -b feature/my-feature`\n3. Commit your changes: `git commit -am 'Add my feature'`\n4. Push to the branch: `git push origin feature/my-feature`\n5. Submit a pull request\n\n## License\n\nThis project is licensed under the MIT License - see the LICENSE file for details.\n\n## Acknowledgments\n\n- Fastify team for the awesome framework\n- Prisma team for the great ORM\n- All the open-source contributors whose tools make this possible\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgubiar%2Freal-world-fastify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgubiar%2Freal-world-fastify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgubiar%2Freal-world-fastify/lists"}