This project is a robust Node.js API template using TypeScript, Express, and Socket.IO AND WebSocket. (Both implementations are included) It's designed to provide a solid foundation for building scalable and maintainable backend applications.
You can test out the existing demonstrative API and websocket either via Postman or the Swagger UI.
- AI: LangChain for AI workflows.
- TypeScript: Full TypeScript support for enhanced developer experience and type safety.
- Express.js: Fast, unopinionated, minimalist web framework for Node.js.
- WebSocket Support: Real-time, bidirectional and event-based communication.
- Socket.IO Support: Real-time, bidirectional and event-based communication with extra features.
- Consistent Server Response: Consistent server response, whether it is an error or a success.
- Error Handling: Centralized error handling, automatically catch errors and handle gracefully.
- Extensible Custom Errors: Extensible custom errors, you can create new errors and add new error codes, attach messages and metadata to existing errors.
- Swagger Documentation: API documentation using OpenAPI 3.0 specification.
- Authentication: JWT-based authentication middleware.
- Logging: Structured logging using Winston.
- Environment Variables: Secure configuration management.
- Code Quality: ESLint and Prettier for consistent code style.
- Hot Reloading: Nodemon for automatic server restarts during development.
- Database: Prisma as the database ORM.
- Strong Linters: ESLint and Prettier for consistent code style.
src/
├── clients/ # API clients (e.g., database clients)
├── controllers/ # Route handlers
├── interfaces/ # TypeScript interfaces
├── lib/ # Shared constants, functions, types
├── middlewares/ # Custom middlewares
├── models/ # Database models
├── services/ # Business logic
├── utils/ # Utility functions
└── llm/ # LangChain AI workflows: agents, flows, graphs, etc.
-
Clone the repository:
git clone <repository-url>
-
Install dependencies:
npm install
-
Set up environment variables:
- Copy
.env.exampleto.env - Fill in the required values
- Copy
-
Run the development server:
npm run dev
-
Access the API at
http://localhost:3000 -
View Swagger documentation at
http://localhost:3000/api-docs
npm run dev: Start the development server with hot reloadingnpm run build: Build the projectnpm start: Start the production servernpm run lint: Run ESLintnpm run prettier-format: Format code with Prettiernpm run type-check: Run TypeScript type checking
Use one or the other, not both. They use the same path, and implementations are more or less the same.
This template includes WebSocket support for real-time, bidirectional communication.
- The WebSocket server is set up in
src/controllers/websocketServer.ts. - The Socket.IO server is set up in
src/controllers/socketServer.ts.
-
WebSocket Path: The WebSocket endpoint is configured using the
WS_PATHenvironment variable. By default, it's set to/ws. -
Authentication: WebSocket connections are authenticated using the same JWT-based authentication as the REST API.
-
Connection: To connect to the WebSocket server, use:
const socket = new WebSocket('ws://localhost:3000/ws');
Remember to include the authentication token in the connection request.
-
Events:
- On connection: The server logs the new connection and sets up user metadata.
- On message: The server echoes back the received message along with the user information.
- On error: The server logs any WebSocket errors.
- On close: The server logs when a connection is closed.
To expand WebSocket functionality:
- Modify
src/controllers/websocketServer.tsto add new event handlers or change existing ones. - Update the
ExtendedWebSocketinterface insrc/interfaces/serverInterfaces.tsif you need to add more metadata to the WebSocket connection. - Implement client-side WebSocket handling in your frontend application to interact with these endpoints.
-
Socket.IO Path: The Socket.IO endpoint is configured using the
WS_PATHenvironment variable. By default, it's set to/ws. -
Authentication: Socket.IO connections are authenticated using the same JWT-based authentication as the REST API.
-
Connection: To connect to the Socket.IO server, use:
const socket = io('http://localhost:3000/ws');
You can specify custom channels to join and listen for events on specific channels. Check out differences in the implementations.
To expand on the current codebase, follow these guidelines:
-
New Routes:
- Add new route files in
src/controllers/ - Update
src/controllers/index.tsto include new routes - Do not execute business logic in the controller, move it to a service
- Add new route files in
-
AI:
- Add new agents, flows, graphs in
src/llm/- Agents are the LLM agents that are used to generate responses
- Flows are the LLM workflows that are used to generate responses, they can utilize agents, tools, and other resources
- Graphs are the LLM state graphs that are used to generate responses, they are used to track the state of the LLM
- Add new agents, flows, graphs in
-
Business Logic:
- Implement new services in
src/services/ - Keep controllers thin, move complex logic to services
- Implement new services in
-
Database Models:
- Add models in
prisma/schema.prismaand - Run
npx prisma migrate dev --name <migration-name>to create a new migration
- Add models in
-
Middleware:
- Create new middleware in
src/middlewares/ - Add to routes or app-wide in
src/index.ts
- Create new middleware in
-
API Documentation:
- Update
docs/swagger.ymlwhen adding or modifying endpoints
- Update
-
Environment Variables:
- Add new variables to
src/lib/config.tsand.env
- Add new variables to
-
Error Handling:
- Create custom error classes in
src/lib/serverErrors.tsas needed
- Create custom error classes in
Remember to maintain the existing code structure and follow the established patterns for consistency.
I prefer Postgres, but you can use any other database supported by Prisma. Check their documentation or you can always ask me as well.
- Change the schema in
prisma/schema.prisma - Run
npx prisma migrate dev --name <migration-name>to create a new migration.- This will create a new migration file in
prisma/migrations/<timestamp>_<migration-name> - This will also generate and update the prisma client
- This will create a new migration file in
- Use the Prisma client in your services. For example:
import prisma from '@clients/prisma';
const user = await prisma.user.findUnique({
where: { id: 1 },
});