A production-ready Node REST API scaffold: Nest + PostgreSQL + TypeORM + JWT.
Changelog · Contributing · 中文文档
A RESTful API scaffold built on Nest and PostgreSQL, meant as the starting point for a real project rather than a toy.
Structure and conventions follow nodepress. TypeORM takes some getting used to if you are coming from raw SQL, but it pays off: it integrates natively with Nest, entities line up with the tables, and the query API stays readable — see the find options.
Server port, database credentials and auth settings all live in src/app.config.ts.
Node >= 20, PostgreSQL, and pnpm.
pnpm install
pnpm start:dev # development, watch mode
pnpm build # compile to dist/
pnpm start:prod # run the compiled output
pnpm lint # eslint
pnpm typecheck # tsc --noEmit
pnpm test # vitest (unit)
pnpm test:e2e # vitest (e2e — needs a reachable database)
pnpm format # prettier --writeHTTP status codes (see src/errors/):
200 |
OK |
201 |
Created (POST) |
400 |
The request was understood but rejected by the business rules |
401 |
Authentication failed |
403 |
Insufficient permissions for the request or its parameters |
404 |
No such resource |
405 |
No such method |
500 |
Server error |
Response shape (see src/interfaces/http.interface.ts):
status—successorerror.message— always present, added by the@HttpProcessordecorator.error— the error from wherever it occurred. Required wheneverstatusiserror, so failures are debuggable.debug— the stack trace, in development only.result— required wheneverstatusissuccess.- list responses:
{ pagination: {...}, data: [...] } - single resources: the resource itself, e.g.
{ title: '', content: ... }
- list responses:
Entry points
| File | Role |
|---|---|
main.ts |
Loads config, starts the app, registers the global services |
app.module.ts |
Root module; composes the feature modules |
app.controller.ts |
Root controller |
app.config.ts |
Everything configurable: database, app, third parties |
app.environment.ts |
Global environment flags |
Request pipeline
request— the request arrivesmiddleware— CORS and origin checksguard— authenticationinterceptor:before— inbound stream (empty in this app)pipe— parameter extraction and validationcontroller— the route handlerservice— the business logicinterceptor:after— response and error formattingfilter— catches anything thrown anywhere above and turns it into an error response
Authentication flow
guardinspects the requestguard.canActivateruns the inherited handlingJwtStrategy.validatecalls the auth serviceguard.handleRequestlets the request through, or blocks it
Authorisation levels
- Every mutating operation (create / update / delete) requires a valid token — see
src/guards/auth.guard.ts. - GET requests that read table data validate the token opportunistically: no token, or a valid token, both pass; an invalid token does not.
Parameter validation (src/decorators/query-params.decorator.ts)
- An ordinary user reaching for an advanced query parameter is treated as unauthorised →
403. - Any request with invalid parameters is stopped by the validator →
400.
Interceptors (src/interceptors/)
- transform — turns a successful service Promise into the standard response shape.
- error — catches a failing service Promise.
- logging — replaces the default global logger.
Decorators (src/decorators/)
- controller response — normalises the output, including
messageand pagination. - query params — validates and formats
query/paramsand the derived metadata.
Guards (src/guards/) — every non-GET request goes through the Auth guard.
Middleware (src/middlewares/) — CORS handling and origin filtering.
Pipes (src/pipes/) — validation.pipe validates everything built on class-validator.
Feature modules (src/modules/) — an Auth module and a Cats demo.
Core processors (src/processors/)
- database — the TypeORM connection.
- helper — email, IP geolocation, SEO submission and Google credentials services.
See CONTRIBUTING.md.