Skip to content

Commit f36b19d

Browse files
style: format changed files with Prettier and exclude .vscode/settings.json from commit
1 parent 06cdba6 commit f36b19d

File tree

7 files changed

+946
-31
lines changed

7 files changed

+946
-31
lines changed

README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,61 @@ Nest is an MIT-licensed open source project. It can grow thanks to the sponsors
9999
## License
100100

101101
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
102+
103+
## API Conventions
104+
105+
### Response Envelope
106+
107+
Endpoints using the custom `@Api({ envelope: true })` decorator option return:
108+
109+
```
110+
{ "success": true, "data": <payload> }
111+
```
112+
113+
Errors are normalized by the global `HttpExceptionFilter` into:
114+
115+
```
116+
{
117+
"success": false,
118+
"error": {
119+
"statusCode": 400,
120+
"message": "Validation failed",
121+
"details": {},
122+
"path": "/endpoint",
123+
"timestamp": "2025-01-01T00:00:00.000Z"
124+
}
125+
}
126+
```
127+
128+
### Pagination Shape
129+
130+
Paginated endpoints (with `paginatedResponseType`) return (inside the envelope when enabled):
131+
132+
```
133+
{
134+
"items": [ ... ],
135+
"pageInfo": {
136+
"hasNextPage": true,
137+
"hasPreviousPage": false,
138+
"startCursor": "0",
139+
"endCursor": "25"
140+
},
141+
"totalCount": 1234,
142+
"meta": { "company": { ... } }
143+
}
144+
```
145+
146+
Use `buildPaginatedResult({ items, skip, take, totalCount, meta })` in services.
147+
148+
### Automatic Swagger Params
149+
150+
Annotate DTO properties with `@Field({ inQuery: true })` or `@Field({ inPath: true })`. Add those DTOs to `queriesFrom` / `pathParamsFrom` in `@Api()` and Swagger params are generated automatically.
151+
152+
### Adding a New Paginated Endpoint
153+
1. Create / reuse DTOs + annotate filters & pagination args with `@Field`.
154+
2. Controller: `@Api({ paginatedResponseType: MyDto, envelope: true, queriesFrom: [PaginationArgs, FilterDto] })`.
155+
3. Service: return `buildPaginatedResult`.
156+
157+
### Error Handling
158+
Throw standard Nest `HttpException` subclasses. The filter wraps them in the envelope. Custom non-Http errors can be mapped by extending the filter if needed.
159+

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"build": "nest build",
1010
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
1111
"start": "nest start",
12-
"start:dev": "nest start --watch",
12+
"start:dev": "NODE_ENV=local nest start --watch",
1313
"start:debug": "nest start --debug --watch",
1414
"start:prod": "node dist/main",
1515
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",

src/auth/auth.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class AuthController {
1717
summary: 'Google authentication',
1818
description: 'Authenticate a user using a Google ID token and optional buildType.',
1919
bodyType: GoogleAuthInput,
20-
envelope: true,
20+
envelope: true,
2121
responses: [
2222
{ status: 200, description: 'Authenticated successfully.' },
2323
{ status: 400, description: 'ID token missing or invalid.' },

src/jobs/job.controller.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ export class JobController {
9494
summary: 'Get jobs by company',
9595
description: 'Retrieves all job listings for a specific company',
9696
pathParamsFrom: CompanyPathParamsDto,
97-
paginatedResponseType: JobDto,
98-
envelope: true,
97+
paginatedResponseType: JobDto,
98+
envelope: true,
9999
queriesFrom: [PaginationArgs],
100100
})
101101
async findByCompany(
@@ -125,8 +125,8 @@ export class JobController {
125125
summary: 'Get jobs by tag',
126126
description: 'Retrieves all job listings that have a specific tag',
127127
pathParamsFrom: TagPathParamsDto,
128-
paginatedResponseType: JobDto,
129-
envelope: true,
128+
paginatedResponseType: JobDto,
129+
envelope: true,
130130
queriesFrom: [PaginationArgs],
131131
})
132132
async findByTag(
@@ -176,8 +176,8 @@ export class JobController {
176176
@Api({
177177
summary: 'Get all job listings',
178178
description: 'Retrieves a paginated list of job listings with optional filtering',
179-
paginatedResponseType: JobDto,
180-
envelope: true,
179+
paginatedResponseType: JobDto,
180+
envelope: true,
181181
queriesFrom: [PaginationArgs, JobFilterQueryDto],
182182
})
183183
async findAll(

src/jobs/job.service.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ export class JobService {
332332
console.log(`First job ID: ${jobs[0].id}, Last job ID: ${jobs[jobs.length - 1].id}`);
333333
}
334334

335-
return buildPaginatedResult({ items: jobs, skip, take, totalCount, meta: null });
335+
return buildPaginatedResult({ items: jobs, skip, take, totalCount, meta: null });
336336
}
337337

338338
/**
@@ -517,7 +517,7 @@ export class JobService {
517517
this.prisma.job.count({ where }),
518518
]);
519519

520-
return buildPaginatedResult({ items: jobs, skip, take, totalCount, meta: { company } });
520+
return buildPaginatedResult({ items: jobs, skip, take, totalCount, meta: { company } });
521521
}
522522

523523
/**
@@ -569,7 +569,7 @@ export class JobService {
569569
this.prisma.job.count({ where }),
570570
]);
571571

572-
return buildPaginatedResult({ items: jobs, skip, take, totalCount, meta: { tag } });
572+
return buildPaginatedResult({ items: jobs, skip, take, totalCount, meta: { tag } });
573573
}
574574

575575
/**

src/metadata.ts

Lines changed: 874 additions & 17 deletions
Large diffs are not rendered by default.

src/notifications/notifications.controller.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export class NotificationsController {
1414
@Api({
1515
summary: 'Get VAPID public key',
1616
description: 'Returns the Web Push VAPID public key for browser clients.',
17-
envelope: true,
17+
envelope: true,
1818
responses: [{ status: 200, description: 'Public key returned.' }],
1919
})
2020
getPublicKey() {
@@ -27,7 +27,7 @@ export class NotificationsController {
2727
summary: 'Create or update push subscription',
2828
description: 'Stores (upserts) a Web Push or FCM subscription tied to the client.',
2929
bodyType: CreateSubscriptionDto,
30-
envelope: true,
30+
envelope: true,
3131
responses: [
3232
{ status: 201, description: 'Subscription stored.' },
3333
{ status: 400, description: 'Invalid subscription payload.' },
@@ -43,7 +43,7 @@ export class NotificationsController {
4343
summary: 'Send a mass notification',
4444
description: 'Sends a notification to all stored subscriptions.',
4545
bodyType: MassNotificationDto,
46-
envelope: true,
46+
envelope: true,
4747
responses: [
4848
{ status: 200, description: 'Mass notification request accepted.' },
4949
{ status: 400, description: 'Invalid notification payload.' },

0 commit comments

Comments
 (0)