This repository provides a Node.js API template to help developers set up an API quickly using TypeScript. It leverages modern tools like Express, Inversify, and Prisma ORM for a clean, modular, and high-performance design.
- Express: A robust HTTP server/router.
- Express Validator: Middleware for validating and sanitizing request data.
- Express FileUpload: Middleware for handling file uploads.
- Body-Parser: Middleware for parsing incoming request bodies.
- Inversify: Dependency injection for managing application services in a clean and maintainable way.
- Inversify-Express-Utils: Helps organize routes and controllers using class-based structure.
- Winston: A flexible logging library.
- JSON Web Token (JWT): Secure authentication using JWT tokens.
- Prisma ORM: A powerful, type-safe ORM with a preset
UserRepository
. - UUID: Utility for generating unique identifiers.
- Bcrypt.js: For hashing passwords.
- Getting Started
- NPM commands
- Controllers
- Distributed Process ID
- Repositories
- Authentication
- Environment Variables
- Logging
- Tests
- Contributing
- Node.js v18 or higher
- NPM (comes with Node.js)
To get started, clone the repository and install dependencies:
git clone [email protected]:irfanh94/nodejs-api-template.git
cd nodejs-api-template
cp .env.dist .env
npm install
npm run build
The template uses Prisma for database management. Before running the project, configure your Prisma connection in the .env file:
DATABASE_URL="mysql://user:password@localhost:3306/db"
DATABASE_CONNECTION_LIMIT=1
Run the following command to apply database migrations:
npm run db:migration:migrate
Once the dependencies are installed and the database is configured, you can run the application:
npm run start:app
npm run build
- build application and prisma modelsnpm run start:app
- application will start on definedAPP_HTTP_PORT
environment variablenpm run db:models:generate
- generate prisma modelsnpm run db:migration:create
- create new migration file based on differences between database and schema.prisma filenpm run db:migration:migrate
- execute database migrationsnpm run test
- execute tests
We use Inversify to handle dependency injection, which allows for clean separation of concerns and easy testing. The src/Kernel/Container.ts
file contains the service container configuration.
Create new service src/Service/NewService.ts
import {injectable} from "inversify";
@injectable()
export class NewService {
}
Register new service in src/Kernel/Containers.ts
container.bind(NewService).toSelf()
Inject service in another class
import {inject, injectable} from "inversify";
@injectable
export class NewClass {
constructor(
@inject(NewService) private readonly newService: NewService
) {}
}
More about InverisfyJS can be fount at: https://www.npmjs.com/package/inversify
This template includes two preset controllers:
- AccountController: Fetches account information using the current JWT token.
- AuthenticateController: Generates a JWT based on the provided email and password.
Both controllers are organized using inversify-express-utils, allowing for clean, class-based routing.
Let's create a file src/Http/Controller/NewController.ts
Now we want to export main controller class, so the content of the file would be:
import {BaseHttpController, controller, httpGet} from "inversify-express-utils";
@controller("/new-controller")
export class NewController extends BaseHttpController {
@httpGet("/new-route")
public newRoute() {
return {foo: "bar"};
}
}
After creating new controller now we need to register it in src/Kernel/Container.ts
by adding:
container.bind(NewController).toSelf();
It's pretty easy by using express-validator
Example:
@httpPost(
"/new-route",
body("email").isEmail().withMessage("email must be valid"),
body("password").isString().isLength({min: 3,}),
RequestValidatorMiddleware
)
public register(request: Request) {
return request.body;
}
This template includes a distributed processId
that can be found in the express.Request
object. The process ID is set in the src/Kernel/Http.ts
file.
If the process-id
header is not present in the incoming request, a new processId
is generated using uuid.v4()
.
This ensures that each request has a unique identifier, which can be useful for logging and tracing purposes across distributed systems.
We utilize Prisma ORM with a UserRepository that provides basic user management operations. You can easily extend the repository for additional models and queries.
More about Prisma can be found at: https://www.prisma.io/docs/getting-started/quickstart
Authentication is based on JSON Web Tokens (JWT). The AuthenticateController provides an endpoint to generate a JWT after validating the user's email and password.
To protect routes, use any of: @httpGet, @httpPost, @httpPut, @httpDelete decorators with a middleware to validate the JWT.
Example route protection:
@httpGet('/account', JwtAuthenticationMiddleware)
public getAccountInfo(request: Request): AccountInfo {
// Your logic here
}
The application requires the following environment variables configured in a .env file:
APP_ENV=dev # application environment
APP_NAME=nodejs-template # application name - can be used for logging or other purposes
APP_SECRET=da4zjgk0i1g7y8ve5h71z0xbubu6c4v4 # application secret - used mainily for jwt
APP_HTTP_PORT=3000
APP_HTTP_BODY_LIMIT=10mb # request size limit
APP_HTTP_CORS=* # used for "cors" package to allow requests from specific domains
DATABASE_URL=mysql://root:dd29a8da323685e91634c15e3c4fc486c39dbb34e063a29c@localhost:3306/test_db
DATABASE_CONNECTION_LIMIT=1 # db connection limit - comes in handy when scaling the application
We use Winston for flexible logging and its configuration is editable under src/Service/Logger.ts
file.
Default log levels: debug, info, error.
Logs are written to the console but can be configured to write to files or external services.
The test suite is located under the ./src/Test
directory and uses the built-in node:test and assert packages for unit testing.
To run the tests, use the following command:
npm run test
This command will first build the project and then execute the tests.
You can overwrite the environment variables specifically for testing by creating a .env.test file. This file allows you to define different configurations for the test environment, which will be used only during test execution.
Example .env.test:
APP_ENV=test
APP_HTTP_PORT=3001
By setting up the .env.test file, you ensure that tests run with a separate configuration from your development environment.
If you'd like to contribute, please fork the repository and use a feature branch. Pull requests are warmly welcomed.
- Fork the repository
- Create your feature branch: git checkout -b my-new-feature
- Commit your changes: git commit -m 'Add some feature'
- Push to the branch: git push origin my-new-feature
- Submit a pull request