Skip to content

Commit d079ca5

Browse files
authored
Merge pull request #10 from storyofams/docs/usage
docs: usage and parameter decorators
2 parents c3d7f3f + 90f6408 commit d079ca5

File tree

1 file changed

+170
-11
lines changed

1 file changed

+170
-11
lines changed

README.md

Lines changed: 170 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,178 @@
55
<h1 align="center">@storyofams/next-api-decorators</h1>
66
</p>
77

8+
<p align="center">Collection of decorators to create structured API routes with Next.js.</p>
9+
10+
---
11+
12+
## Installation
13+
14+
Add the package to your project:
15+
16+
```bash
17+
$ yarn add @storyofams/next-api-decorators
18+
```
19+
20+
Since decorators are still in proposal state, you need to add the following plugins to your `devDependencies` in order to use them:
21+
22+
```bash
23+
$ yarn add -D babel-plugin-transform-typescript-metadata @babel/plugin-proposal-decorators babel-plugin-parameter-decorator
24+
```
25+
26+
Your `tsconfig.json` needs the following flags:
27+
28+
```json
29+
"experimentalDecorators": true,
30+
"emitDecoratorMetadata": true
31+
```
32+
33+
## Usage
34+
35+
### Basic example
36+
37+
```ts
38+
// pages/api/user.ts
39+
import {
40+
createHandler,
41+
Get,
42+
Post,
43+
HttpCode,
44+
Query,
45+
Body,
46+
NotFoundException
47+
} from '@storyofams/next-api-decorators';
48+
49+
class User {
50+
// GET /api/user
51+
@Get()
52+
public async fetchUser(@Query('id') id: string) {
53+
const user = await User.findById(id);
54+
55+
if (!user) {
56+
throw new NotFoundException('User not found.');
57+
}
58+
59+
return user;
60+
}
61+
62+
// POST /api/user
63+
@Post()
64+
@HttpCode(201)
65+
public createUser(@Body() body: any) {
66+
return User.create(body);
67+
}
68+
}
69+
70+
export default createHandler(User);
71+
```
72+
73+
### Data transfer object
74+
75+
If you want to use `class-validator` to validate request bodies and get them as DTOs, add it to your project by running:
76+
77+
```bash
78+
$ yarn add class-validator class-transformer
79+
```
80+
81+
Then you can define your DTOs like:
82+
83+
```ts
84+
import { createHandler, Post, Body } from '@storyofams/next-api-decorators';
85+
import { IsNotEmpty, IsEmail } from 'class-validator';
86+
87+
class CreateUserDto {
88+
@IsNotEmpty()
89+
public name: string;
90+
91+
@IsEmail()
92+
public email: string;
93+
}
94+
95+
class User {
96+
@Post()
97+
public createUser(@Body() body: CreateUserDto) {
98+
return User.create(body);
99+
}
100+
}
101+
102+
export default createHandler(User);
103+
```
104+
8105
## Available decorators
9106

10107
### Class decorators
11-
| | Description |
12-
| ---- | ----------- |
13-
| `SetHeader` | Sets a header value into the response for all routes defined in the class.
108+
109+
| | Description |
110+
| ----------- | -------------------------------------------------------------------------- |
111+
| `SetHeader` | Sets a header value into the response for all routes defined in the class. |
14112

15113
### Method decorators
16-
| | Description |
17-
| --- | ----------- |
18-
| `Get` | Marks the method as `GET` method handler.
19-
| `Post` | Marks the method as `POST` method handler.
20-
| `Put` | Marks the method as `PUT` method handler.
21-
| `Delete` | Marks the method as `DELETE` method handler.
22-
| `SetHeader` | Sets a header key/value into the response for the route.
23-
| `HttpCode` | Sets the http code the route response.
114+
115+
| | Description |
116+
| ----------- | --------------------------------------------------------- |
117+
| `Get` | Marks the method as `GET` handler. |
118+
| `Post` | Marks the method as `POST` handler. |
119+
| `Put` | Marks the method as `PUT` handler. |
120+
| `Delete` | Marks the method as `DELETE` handler. |
121+
| `SetHeader` | Sets a header name/value into the response for the route. |
122+
| `HttpCode` | Sets the http code the route response. |
123+
124+
### Parameter decorators
125+
126+
| | Description |
127+
| ----------------------- | ------------------------------------------- |
128+
| `@Body()` | Gets the request body. |
129+
| `@Query(key: string)` | Gets a query string parameter value by key. |
130+
| `@Header(name: string)` | Gets a header value by name. |
131+
132+
133+
134+
135+
## Built-in pipes
136+
137+
Pipes are being used to validate and transform incoming values. The pipes can be added to the `@Query` decorator like:
138+
139+
```ts
140+
@Query('isActive', ParseBooleanPipe) isActive: boolean
141+
```
142+
143+
⚠️ Beware that they throw when the value is invalid.
144+
145+
| | Description | Remarks |
146+
| ------------------ | -------------------------------------------- | --------------------------------------------- |
147+
| `ParseNumberPipe` | Validates and transforms `Number` strings. | Uses `parseFloat` under the hood |
148+
| `ParseBooleanPipe` | Validates and transforms `Boolean` strings. | Allows `'true'` and `'false'` as valid values |
149+
150+
151+
## Exceptions
152+
153+
The following built-in exceptions are provided by this package:
154+
155+
* `NotFoundException`
156+
* `BadRequestException`
157+
158+
159+
### Custom exceptions
160+
161+
Any exception class that extends the base `HttpException` will be handled by the built-in error handler.
162+
163+
```ts
164+
import { HttpException } from '@storyofams/next-api-decorators';
165+
166+
export class ForbiddenException extends HttpException {
167+
public constructor(message?: string) {
168+
super(403, message);
169+
}
170+
}
171+
```
172+
173+
Then later in the app, we can use it in our route handler:
174+
175+
```ts
176+
class Events {
177+
@Get()
178+
public events() {
179+
throw new ForbiddenException();
180+
}
181+
}
182+
```

0 commit comments

Comments
 (0)