nestia 2.1.2 → 2.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +666 -449
- package/lib/analyses/ControllerAnalyzer.d.ts.map +1 -1
- package/lib/analyses/ControllerAnalyzer.js +34 -7
- package/lib/analyses/ReflectAnalyzer.d.ts.map +1 -1
- package/lib/analyses/ReflectAnalyzer.js +51 -18
- package/lib/generates/SwaggerGenerator.d.ts.map +1 -1
- package/lib/generates/SwaggerGenerator.js +4 -4
- package/lib/structures/IController.d.ts +2 -2
- package/lib/structures/IController.d.ts.map +1 -1
- package/lib/structures/ISwagger.d.ts +5 -3
- package/lib/structures/ISwagger.d.ts.map +1 -1
- package/package.json +2 -2
- package/lib/factories/CommentFactory.d.ts +0 -5
- package/lib/factories/CommentFactory.d.ts.map +0 -1
- package/lib/factories/CommentFactory.js +0 -14
- package/lib/factories/MetadataCollection.d.ts +0 -14
- package/lib/factories/MetadataCollection.d.ts.map +0 -1
- package/lib/factories/MetadataCollection.js +0 -83
- package/lib/factories/MetadataFactory.d.ts +0 -8
- package/lib/factories/MetadataFactory.d.ts.map +0 -1
- package/lib/factories/MetadataFactory.js +0 -251
- package/lib/factories/SchemaFactory.d.ts +0 -9
- package/lib/factories/SchemaFactory.d.ts.map +0 -1
- package/lib/factories/SchemaFactory.js +0 -179
package/README.md
CHANGED
|
@@ -1,373 +1,474 @@
|
|
|
1
1
|
# Nestia
|
|
2
|
-
Automatic `SDK` and `
|
|
3
|
-
|
|
4
|
-
[](https://github.com/samchon/nestia/blob/master/LICENSE)
|
|
5
|
-
[](https://www.npmjs.com/package/nestia)
|
|
6
|
-
[](https://www.npmjs.com/package/nestia)
|
|
7
|
-
[](https://github.com/samchon/nestia/actions?query=workflow%3Abuild)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
You just run this [nestia](https://github.com/samchon/nestia) up, then [nestia](https://github.com/samchon/nestia) would generate the SDK automatically, by analyzing your controller classes in the compliation and runtime level. With the automatically generated SDK through this [nestia](https://github.com/samchon/nestia), client developer also does not need any extra work, like reading `swagger` and writing the duplicated interaction code. Client developer only needs to import the SDK and calls matched function with the `await` symbol.
|
|
33
|
-
|
|
34
|
-
> Even generating the `swagger.json` without any swagger comment and DTO decorator is also possible. When generating the `swagger.json`, no DTO comment and decorator is required, either. Use only the pure interface definitions.
|
|
2
|
+
Automatic `SDK` and `Swagger` generator for the `NestJS`, evolved than ever.
|
|
3
|
+
|
|
4
|
+
[](https://github.com/samchon/nestia/blob/master/LICENSE)
|
|
5
|
+
[](https://www.npmjs.com/package/nestia)
|
|
6
|
+
[](https://www.npmjs.com/package/nestia)
|
|
7
|
+
[](https://github.com/samchon/nestia/actions?query=workflow%3Abuild)
|
|
8
|
+
[](https://github.com/samchon/nestia/wiki)
|
|
9
|
+
|
|
10
|
+
- Github: https://github.com/samchon/nestia
|
|
11
|
+
- NPM: https://www.npmjs.com/packages/nestia
|
|
12
|
+
- Guide Documents: https://github.com/samchon/nestia/wiki
|
|
13
|
+
|
|
14
|
+
`nestia` is an evolved `SDK` and `Swagger` generator, which analyzes your `NestJS` server code in the compilation level. With `nestia` and compilation level analyzer, you don't need to write any swagger or class-validator decorators. All you need to do is use the `nestia` CLI as shown below.
|
|
15
|
+
|
|
16
|
+
Reading below contents, feel how the "compilation level" makes `nestia` stronger.
|
|
17
|
+
|
|
18
|
+
Components | `nestia`::SDK | `nestia`::swagger | `@nestjs/swagger`
|
|
19
|
+
-----------|---|---|---
|
|
20
|
+
Pure DTO interface | ✔ | ✔ | ❌
|
|
21
|
+
Description comments | ✔ | ✔ | ❌
|
|
22
|
+
Simple structure | ✔ | ✔ | ✔
|
|
23
|
+
Generic type | ✔ | ✔ | ❌
|
|
24
|
+
Union type | ✔ | ✔ | ▲
|
|
25
|
+
Intersection type | ✔ | ✔ | ▲
|
|
26
|
+
Conditional type | ✔ | ▲ | ❌
|
|
27
|
+
Auto completion | ✔ | ❌ | ❌
|
|
28
|
+
Type hints | ✔ | ❌ | ❌
|
|
29
|
+
2x faster `JSON.stringify()` | ✔ | ❌ | ❌
|
|
30
|
+
Ensure type safety | ✅ | ❌ | ❌
|
|
35
31
|
|
|
36
32
|
```typescript
|
|
37
|
-
|
|
38
|
-
import
|
|
39
|
-
import { IPage } from "@samchon/
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
// IMPORT SDK LIBRARY GENERATED BY NESTIA
|
|
34
|
+
import api from "@samchon/shopping-api";
|
|
35
|
+
import { IPage } from "@samchon/shopping-api/lib/structures/IPage";
|
|
36
|
+
import { ISale } from "@samchon/shopping-api/lib/structures/ISale";
|
|
37
|
+
import { ISaleArticleComment } from "@samchon/shopping-api/lib/structures/ISaleArticleComment";
|
|
38
|
+
import { ISaleQuestion } from "@samchon/shopping-api/lib/structures/ISaleQuestion";
|
|
39
|
+
|
|
40
|
+
export async function trace_sale_question_and_comment
|
|
41
|
+
(connection: api.IConnection): Promise<void>
|
|
42
42
|
{
|
|
43
|
-
// LIST UP
|
|
44
|
-
const index: IPage<
|
|
43
|
+
// LIST UP SALE SUMMARIES
|
|
44
|
+
const index: IPage<ISale.ISummary> = await api.functional.shoppings.sales.index
|
|
45
45
|
(
|
|
46
46
|
connection,
|
|
47
|
-
"
|
|
47
|
+
"general",
|
|
48
48
|
{ limit: 100, page: 1 }
|
|
49
49
|
);
|
|
50
50
|
|
|
51
|
-
//
|
|
52
|
-
const
|
|
51
|
+
// PICK A SALE
|
|
52
|
+
const sale: ISale = await api.functional.shoppings.sales.at
|
|
53
53
|
(
|
|
54
|
-
connection,
|
|
55
|
-
"free",
|
|
54
|
+
connection,
|
|
56
55
|
index.data[0].id
|
|
57
56
|
);
|
|
58
|
-
console.log(
|
|
57
|
+
console.log("sale", sale);
|
|
58
|
+
|
|
59
|
+
// WRITE A QUESTION
|
|
60
|
+
const question: ISaleQuestion = await api.functional.shoppings.sales.questions.store
|
|
61
|
+
(
|
|
62
|
+
connection,
|
|
63
|
+
"general",
|
|
64
|
+
sale.id,
|
|
65
|
+
{
|
|
66
|
+
title: "How to use this product?",
|
|
67
|
+
body: "The description is not fully enough. Can you introduce me more?",
|
|
68
|
+
files: []
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
console.log("question", question);
|
|
72
|
+
|
|
73
|
+
// WRITE A COMMENT
|
|
74
|
+
const comment: ISaleArticleComment = await api.functional.shoppings.sales.comments.store
|
|
75
|
+
(
|
|
76
|
+
connection,
|
|
77
|
+
"general",
|
|
78
|
+
sale.id,
|
|
79
|
+
question.id,
|
|
80
|
+
{
|
|
81
|
+
body: "p.s) Can you send me a detailed catalogue?",
|
|
82
|
+
anonymous: false
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
console.log("comment", comment);
|
|
59
86
|
}
|
|
60
87
|
```
|
|
61
88
|
|
|
62
89
|
|
|
63
90
|
|
|
91
|
+
## Setup
|
|
92
|
+
Just like any other package, you've got to install it before you can use it.
|
|
64
93
|
|
|
65
|
-
|
|
66
|
-
### Installation
|
|
67
|
-
```bash
|
|
94
|
+
```sh
|
|
68
95
|
npm install --save-dev nestia
|
|
69
96
|
```
|
|
70
97
|
|
|
71
|
-
|
|
98
|
+
After the installation, you can generate the `SDK` or `Swagger`, directly.
|
|
72
99
|
|
|
73
|
-
|
|
100
|
+
```sh
|
|
101
|
+
npx nestia sdk "src/**/*.controller" --out "src/api"
|
|
102
|
+
npx nestia swagger "src/**/*.controller" --out "swagger.json"
|
|
103
|
+
```
|
|
74
104
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
105
|
+
> If all of your controller files are gathered into one directory:
|
|
106
|
+
>
|
|
107
|
+
> ```sh
|
|
108
|
+
> npx nestia sdk "src/controllers" --out "src/api"
|
|
109
|
+
> npx nestia swagger "src/controllers" --out "swagger.json"
|
|
110
|
+
> ```
|
|
111
|
+
>
|
|
112
|
+
> You can omit all of the parameters if you've configured the [nestia.config.ts](#configuration) file.
|
|
113
|
+
>
|
|
114
|
+
> ```sh
|
|
115
|
+
> npx nestia sdk
|
|
116
|
+
> npx nestia swagger
|
|
117
|
+
> ```
|
|
78
118
|
|
|
79
|
-
npx nestia sdk "src/**/*.controller.ts" --out "src/api"
|
|
80
|
-
npx nestia sdk "src/controllers" --out "src/api"
|
|
81
|
-
npx nestia sdk "src/controllers/consumers" "src/controllers/sellers" --out "src/api"
|
|
82
|
-
npx nestia sdk "src/controllers" --exclude "src/**/Fake*.ts" --out "src/api"
|
|
83
|
-
```
|
|
84
119
|
|
|
85
|
-
To generate a SDK library through the [nestia](https://github.com/samchon/nestia) is very easy.
|
|
86
120
|
|
|
87
|
-
Just type the `nestia sdk <input> --out <output>` command in the console. When there're multiple source directories containing the NestJS controller classes, type all of them separating by a `space` word. If you want to exclude some directories or files from the SDK generation, the `--exclude` option would be useful.
|
|
88
121
|
|
|
89
|
-
|
|
122
|
+
## Demonstrations
|
|
123
|
+
### Pure DTO Interface
|
|
124
|
+
`nestia` can utilize pure interface type as DTO.
|
|
90
125
|
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
npx nestia <source_controller_of_directory> --out <output_path>
|
|
126
|
+
Unlike `@nestjs/swagger` which requires the DTO class with decorators, `nestia` can use the pure interface type directly. Also, `nestia` can utilize the pure descriptive comments, instead of using the `description` property of the decorators. Furthermore, `nestia` can even support generic types, union/intersection types and even conditional types.
|
|
94
127
|
|
|
95
|
-
|
|
96
|
-
npx nestia swagger "src/controllers" --out "./swagger.json"
|
|
97
|
-
npx nestia swagger "src/consumers" "src/sellers" --out "actors.json"
|
|
98
|
-
npx nestia swagger "src/controllers" --exclude "src/**/Fake*.ts" -out "./"
|
|
99
|
-
```
|
|
128
|
+
Look at the code below, you may see the difference between `nestia` and `@nestjs/swagger`, and thereby catch the meaning of the pure DTO interface.
|
|
100
129
|
|
|
101
|
-
|
|
130
|
+
- Simple [`ISaleArticleComment`](https://github.com/samchon/nestia/tree/master/demo/simple/src/api/structures/ISaleArticleComment.ts)
|
|
131
|
+
- Generic interfaces
|
|
132
|
+
- grandparent interface, [`ISaleArticle<Content>`](https://github.com/samchon/nestia/tree/master/demo/generic/src/api/structures/ISaleArticle.ts)
|
|
133
|
+
- parent interface, [`ISaleInquiry<Content>`](https://github.com/samchon/nestia/tree/master/demo/generic/src/api/structures/ISaleInquiry.ts)
|
|
134
|
+
- 1st sub-type interface, [`ISaleQuestion`](https://github.com/samchon/nestia/tree/master/demo/generic/src/api/structures/ISaleQuestion.ts)
|
|
135
|
+
- 2nd sub-type interface, [`ISaleReview`](https://github.com/samchon/nestia/tree/master/demo/generic/src/api/structures/ISaleReview.ts)
|
|
136
|
+
- Union alias type [`ISaleEntireArticle`](https://github.com/samchon/nestia/tree/master/demo/union/src/api/structures/ISaleEntireArticle.ts)
|
|
102
137
|
|
|
103
|
-
|
|
138
|
+
> The below example code would be shown by clicking the arrow button or text.
|
|
104
139
|
|
|
105
|
-
|
|
140
|
+
<details>
|
|
141
|
+
<summary>
|
|
142
|
+
Traditional DTO class using <code>@nestjs/swagger</code>
|
|
143
|
+
</summary>
|
|
106
144
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
145
|
+
```typescript
|
|
146
|
+
export class SaleArticleComment
|
|
147
|
+
{
|
|
148
|
+
@ApiProperty({
|
|
149
|
+
description:
|
|
150
|
+
`Comment wrote on a sale related article.
|
|
111
151
|
|
|
112
|
-
|
|
152
|
+
When an article of a sale has been enrolled, all of the participants like consumers and sellers can write a comment on that article. However, when the writer is a consumer, the consumer can hide its name through the annoymous option.
|
|
113
153
|
|
|
114
|
-
|
|
154
|
+
Also, writing a reply comment for a specific comment is possible and in that case, the ISaleArticleComment.parent_id property would be activated.`
|
|
155
|
+
})
|
|
156
|
+
id: number;
|
|
115
157
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
158
|
+
@ApiProperty({
|
|
159
|
+
type: "number",
|
|
160
|
+
nullable: true,
|
|
161
|
+
description:
|
|
162
|
+
`Parent comment ID.
|
|
163
|
+
|
|
164
|
+
Only When this comment has been written as a reply.`
|
|
165
|
+
})
|
|
166
|
+
parent_id: number | null;
|
|
167
|
+
|
|
168
|
+
@ApiProperty({
|
|
169
|
+
type: "string",
|
|
170
|
+
description: "Type of the writer."
|
|
171
|
+
})
|
|
172
|
+
writer_type: "seller" | "consumer";
|
|
173
|
+
|
|
174
|
+
@ApiProperty({
|
|
175
|
+
type: "string",
|
|
176
|
+
nullable: true,
|
|
177
|
+
description:
|
|
178
|
+
`Name of the writer.
|
|
179
|
+
|
|
180
|
+
When this is a type of anonymous comment, writer name would be hidden.`
|
|
181
|
+
})
|
|
182
|
+
writer_name: string | null;
|
|
183
|
+
|
|
184
|
+
@ApiProperty({
|
|
185
|
+
type: "array",
|
|
186
|
+
items: {
|
|
187
|
+
schema: { $ref: getSchemaPath(SaleArticleComment.Content) }
|
|
188
|
+
},
|
|
189
|
+
description:
|
|
190
|
+
`Contents of the comments.
|
|
191
|
+
|
|
192
|
+
When the comment writer tries to modify content, it would not modify the comment content but would be accumulated Therefore, all of the people can read how the content has been changed.`
|
|
193
|
+
})
|
|
194
|
+
contents: SaleArticleComment.Content[];
|
|
195
|
+
|
|
196
|
+
@ApiProperty({
|
|
197
|
+
description: "Creation time."
|
|
198
|
+
})
|
|
199
|
+
created_at: string;
|
|
124
200
|
}
|
|
125
201
|
```
|
|
202
|
+
</details>
|
|
126
203
|
|
|
204
|
+
<details>
|
|
205
|
+
<summary>
|
|
206
|
+
Pure DTO interface using <code>nestia</code>
|
|
207
|
+
</summary>
|
|
127
208
|
|
|
128
|
-
|
|
129
|
-
## Advanced
|
|
130
|
-
### `nestia.config.ts`
|
|
131
209
|
```typescript
|
|
132
210
|
/**
|
|
133
|
-
*
|
|
211
|
+
* Comment wrote on a sale related article.
|
|
212
|
+
*
|
|
213
|
+
* When an article of a sale has been enrolled, all of the participants like consumers and
|
|
214
|
+
* sellers can write a comment on that article. However, when the writer is a consumer, the
|
|
215
|
+
* consumer can hide its name through the annoymous option.
|
|
216
|
+
*
|
|
217
|
+
* Also, writing a reply comment for a specific comment is possible and in that case, the
|
|
218
|
+
* {@link ISaleArticleComment.parent_id} property would be activated.
|
|
134
219
|
*
|
|
135
220
|
* @author Jeongho Nam - https://github.com/samchon
|
|
136
221
|
*/
|
|
137
|
-
export interface
|
|
222
|
+
export interface ISaleArticleComment
|
|
138
223
|
{
|
|
139
224
|
/**
|
|
140
|
-
*
|
|
225
|
+
* Primary Key.
|
|
141
226
|
*/
|
|
142
|
-
|
|
227
|
+
id: number;
|
|
143
228
|
|
|
144
229
|
/**
|
|
145
|
-
*
|
|
230
|
+
* Parent comment ID.
|
|
231
|
+
*
|
|
232
|
+
* Only When this comment has been written as a reply.
|
|
146
233
|
*/
|
|
147
|
-
|
|
234
|
+
parent_id: number | null;
|
|
148
235
|
|
|
149
236
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* If omitted, the configuration would follow the `tsconfig.json`.
|
|
237
|
+
* Type of the writer.
|
|
153
238
|
*/
|
|
154
|
-
|
|
239
|
+
writer_type: "seller" | "consumer";
|
|
155
240
|
|
|
156
241
|
/**
|
|
157
|
-
*
|
|
242
|
+
* Name of the writer.
|
|
158
243
|
*
|
|
159
|
-
*
|
|
160
|
-
* checked through the [typescript-is](https://github.com/woutervh-/typescript-is).
|
|
244
|
+
* When this is a type of anonymous comment, writer name would be hidden.
|
|
161
245
|
*/
|
|
162
|
-
|
|
246
|
+
writer_name: string | null;
|
|
163
247
|
|
|
164
248
|
/**
|
|
165
|
-
*
|
|
249
|
+
* Contents of the comments.
|
|
166
250
|
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
251
|
+
* When the comment writer tries to modify content, it would not modify the comment
|
|
252
|
+
* content but would be accumulated. Therefore, all of the people can read how
|
|
253
|
+
* the content has been changed.
|
|
170
254
|
*/
|
|
171
|
-
|
|
255
|
+
contents: ISaleArticleComment.IContent[];
|
|
172
256
|
|
|
173
257
|
/**
|
|
174
|
-
*
|
|
258
|
+
* Creation time.
|
|
175
259
|
*/
|
|
176
|
-
|
|
260
|
+
created_at: string;
|
|
177
261
|
}
|
|
178
|
-
export namespace
|
|
262
|
+
export namespace ISaleArticleComment
|
|
179
263
|
{
|
|
180
264
|
/**
|
|
181
|
-
*
|
|
182
|
-
* controllers.
|
|
265
|
+
* Store info.
|
|
183
266
|
*/
|
|
184
|
-
export interface
|
|
267
|
+
export interface IStore
|
|
185
268
|
{
|
|
186
269
|
/**
|
|
187
|
-
*
|
|
270
|
+
* Body of the content.
|
|
188
271
|
*/
|
|
189
|
-
|
|
272
|
+
body: string;
|
|
190
273
|
|
|
191
274
|
/**
|
|
192
|
-
*
|
|
275
|
+
* Whether to hide the writer name or not.
|
|
193
276
|
*/
|
|
194
|
-
|
|
277
|
+
annonymous: boolean;
|
|
195
278
|
}
|
|
196
279
|
|
|
197
280
|
/**
|
|
198
|
-
*
|
|
281
|
+
* Content info.
|
|
199
282
|
*/
|
|
200
|
-
export interface
|
|
283
|
+
export interface IContent
|
|
201
284
|
{
|
|
202
285
|
/**
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
* If you've configure only directory, the file name would be `swagger.json`.
|
|
206
|
-
* Otherwise you configure file name and extension, the `swagger.json` file would
|
|
207
|
-
* be renamed to what you've configured.
|
|
286
|
+
* Primary Key.
|
|
208
287
|
*/
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
Instead of specifying `input` and `output` directories using the cli options, you can specify those directories as an independent configuration file. It's the `nestia.config.ts` and with the `nestia.config.ts` file, you also configure independent TypeScript compiler option from the `tsconfig.json`.
|
|
215
|
-
|
|
216
|
-
Write below content as the `nestia.config.ts` file and place it onto the root directory of your backend project. After the configuration, you can generate the SDK only with the `npx nestia sdk` command, without any directory specification.
|
|
288
|
+
id: string;
|
|
217
289
|
|
|
218
|
-
|
|
219
|
-
|
|
290
|
+
/**
|
|
291
|
+
* Body of the content.
|
|
292
|
+
*/
|
|
293
|
+
body: string;
|
|
220
294
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
|
|
295
|
+
/**
|
|
296
|
+
* Creation time.
|
|
297
|
+
*/
|
|
298
|
+
created_at: string;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
227
301
|
```
|
|
302
|
+
</details>
|
|
228
303
|
|
|
229
|
-
>
|
|
230
|
-
>
|
|
231
|
-
>
|
|
232
|
-
>
|
|
233
|
-
> input: "src/**/*.controller.ts",
|
|
234
|
-
> /* input: {
|
|
235
|
-
> include: ["src/controllers/**\/*.controller.ts"],
|
|
236
|
-
> exclude: ["src/controllers/**\/fake_*.controller.ts"]
|
|
237
|
-
> },*/
|
|
238
|
-
> output: "src/api",
|
|
239
|
-
> assert: true
|
|
240
|
-
> }
|
|
241
|
-
> ```
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
### Recommended Structures
|
|
246
|
-
When developing a NestJS backend server with this [nestia](https://github.com/samchon/nestia), I recommend you to follow below directory structure. The key princinple of below structure is to gathering all of the DTO interface structures into the `src/api/structures` directory and gather all of the controller classes into the `src/controllers` directory.
|
|
247
|
-
|
|
248
|
-
If you place the SDK onto the `src/api` directory and gather all of the DTO interface structures into the `src/api/structures` directory, you can publish the SDK library very easily without any special configuration. Also when you're develop the test automation program, you can implement the API testing features very convenienty through the automatically generated SDK through this [nestia](https://github.com/samchon/nestia).
|
|
249
|
-
|
|
250
|
-
- src
|
|
251
|
-
- api
|
|
252
|
-
- **functional**: automatically generated SDK functions
|
|
253
|
-
- **structures**: DTO structures
|
|
254
|
-
- controllers
|
|
255
|
-
- providers
|
|
256
|
-
- models
|
|
257
|
-
- **test**: Test automation program using SDK functions
|
|
258
|
-
- package.json
|
|
259
|
-
- tsconfig.json
|
|
260
|
-
- nestia.config.ts
|
|
261
|
-
|
|
262
|
-
For your deep understanding about this directory structure with this [nestia](https://github.com/samchon/nestia), I've prepared an example backend project. Looking around the example repository and reading the [README.md](https://github.com/samchon/backend#13-directories) of it, you can feel that such directory structure is how convenient for SDK publishing and test automation program implementation.
|
|
263
|
-
|
|
264
|
-
- https://github.com/samchon/backend
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
## Demonstration
|
|
270
|
-
To demonstrate which SDK codes would be generated by this [nestia](https://github.com/samchon/nestia):
|
|
271
|
-
|
|
272
|
-
- Representative files
|
|
273
|
-
- [DTO interface used in the RestAPI](https://github.com/samchon/nestia/tree/master/demo/simple/src/api/structures/ISaleArticleComment.ts)
|
|
274
|
-
- [Controllers of the NestJS](https://github.com/samchon/nestia/tree/master/demo/simple/src/controllers/ConsumerSaleArticleCommentsController.ts)
|
|
275
|
-
- [SDK generated by this **nestia**](https://github.com/samchon/nestia/tree/master/demo/simple/src/api/functional/consumers/sales/articles/comments/index.ts)
|
|
276
|
-
- [`swagger.json` generated by this **nestia**](https://github.com/samchon/nestia/tree/master/demo/simple/swagger.json)
|
|
277
|
-
- Demonstration Projects
|
|
278
|
-
- [encrypt](https://github.com/samchon/nestia/tree/master/demo/encrypt): Request and response body are fully encrypted
|
|
279
|
-
- [generic](https://github.com/samchon/nestia/tree/master/demo/generic): Generic typed controller classes
|
|
280
|
-
- [recursive](https://github.com/samchon/nestia/tree/master/demo/recursive): Recursive DTO interface, [swagger editor](https://editor.swagger.io) can't expresss it
|
|
281
|
-
- [simple](https://github.com/samchon/nestia/tree/master/demo/simple): Simple DTO interface and controller class
|
|
282
|
-
- [union](https://github.com/samchon/nestia/tree/master/demo/union): Only [nestia](https://github.com/samchon/nestia) can handle the union typed DTO interface
|
|
283
|
-
|
|
284
|
-
### DTO
|
|
285
|
-
Using pure interface type as DTO is possible.
|
|
286
|
-
|
|
287
|
-
You dont' need to define any extra comment or decorator function to make the DTO (Data Transfer Object). Just define the DTO as a pure interface structure, then [nestia](https://github.com/samchon/nestia) will do everything instead of you.
|
|
288
|
-
|
|
289
|
-
If you're afraiding because your type is union or intersection, I can say that it does not matter. Even when generic or conditional type comes, it does not matter. Just enjoy the pure TypeScript type.
|
|
304
|
+
<details>
|
|
305
|
+
<summary>
|
|
306
|
+
Generic typed DTO using <code>nestia</code>
|
|
307
|
+
</summary>
|
|
290
308
|
|
|
291
309
|
```typescript
|
|
292
310
|
/**
|
|
293
|
-
*
|
|
311
|
+
* Inquiry article.
|
|
294
312
|
*
|
|
313
|
+
* Sub-type of article and super-type of question and answer.
|
|
314
|
+
*
|
|
315
|
+
* - List of the sub-types
|
|
316
|
+
* - {@link ISaleQuestion}
|
|
317
|
+
* - {@link ISaleReview}
|
|
318
|
+
*
|
|
319
|
+
* @template Content Content type
|
|
295
320
|
* @author Jeongho Nam - https://github.com/samchon
|
|
296
321
|
*/
|
|
297
|
-
export interface
|
|
322
|
+
export interface ISaleInquiry<Content extends ISaleInquiry.IContent>
|
|
323
|
+
extends ISaleArticle<Content>
|
|
298
324
|
{
|
|
299
325
|
/**
|
|
300
326
|
* Primary Key.
|
|
301
327
|
*/
|
|
302
328
|
id: number;
|
|
303
329
|
|
|
304
|
-
/**
|
|
305
|
-
* Type of the writer.
|
|
306
|
-
*/
|
|
307
|
-
writer_type: "seller" | "consumer";
|
|
308
|
-
|
|
309
330
|
/**
|
|
310
331
|
* Name of the writer.
|
|
311
332
|
*/
|
|
312
|
-
|
|
333
|
+
writer: string;
|
|
313
334
|
|
|
314
335
|
/**
|
|
315
|
-
*
|
|
336
|
+
* List of contents.
|
|
316
337
|
*
|
|
317
|
-
* When the
|
|
318
|
-
* content but would be accumulated. Therefore, all
|
|
338
|
+
* When the article writer tries to modify content, it would not modify the article
|
|
339
|
+
* content but would be accumulated. Therefore, all the people can read how
|
|
319
340
|
* the content has been changed.
|
|
320
341
|
*/
|
|
321
|
-
contents:
|
|
342
|
+
contents: Content[];
|
|
322
343
|
|
|
323
344
|
/**
|
|
324
345
|
* Creation time.
|
|
325
346
|
*/
|
|
326
|
-
|
|
347
|
+
createdAat: string;
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Formal answer from the seller.
|
|
351
|
+
*/
|
|
352
|
+
answer: ISaleInquiryAnswer | null;
|
|
327
353
|
}
|
|
328
|
-
|
|
329
|
-
export namespace ISaleComment
|
|
354
|
+
export namespace ISaleInquiry
|
|
330
355
|
{
|
|
331
356
|
/**
|
|
332
|
-
*
|
|
357
|
+
* Content info.
|
|
333
358
|
*/
|
|
334
|
-
export interface
|
|
359
|
+
export interface IContent
|
|
335
360
|
{
|
|
361
|
+
/**
|
|
362
|
+
* Primary Key
|
|
363
|
+
*/
|
|
364
|
+
id: string;
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Title of the content.
|
|
368
|
+
*/
|
|
369
|
+
title: string;
|
|
370
|
+
|
|
336
371
|
/**
|
|
337
372
|
* Body of the content.
|
|
338
373
|
*/
|
|
339
374
|
body: string;
|
|
340
|
-
}
|
|
341
375
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
376
|
+
/**
|
|
377
|
+
* Attached files.
|
|
378
|
+
*/
|
|
379
|
+
files: IAttachmentFile[];
|
|
380
|
+
|
|
347
381
|
/**
|
|
348
382
|
* Creation time.
|
|
349
383
|
*/
|
|
350
|
-
|
|
384
|
+
createdAt: string;
|
|
351
385
|
}
|
|
352
386
|
}
|
|
353
387
|
```
|
|
388
|
+
</details>
|
|
389
|
+
|
|
390
|
+
<details>
|
|
391
|
+
<summary>
|
|
392
|
+
Union typed DTO using <code>nestia</code>
|
|
393
|
+
</summary>
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
/**
|
|
397
|
+
* Union type of the entire sub-type articles.
|
|
398
|
+
*
|
|
399
|
+
* @author Jeongho Nam - https://github.com/samchon
|
|
400
|
+
*/
|
|
401
|
+
export type ISaleEntireArtcle = ISaleQuestion | ISaleReview;
|
|
402
|
+
```
|
|
403
|
+
</details>
|
|
354
404
|
|
|
355
|
-
|
|
356
|
-
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
### Advanced Controller Class
|
|
409
|
+
Controller also can use the generic arguments.
|
|
410
|
+
|
|
411
|
+
In the previous [Pure DTO Interface](#pure-dto-interface) corner, we've learned that `nestia` can use the pure interface type as DTO. Also, we've learned that utilizing generic, union/intersection and even conditional typed interfaces are also possible.
|
|
412
|
+
|
|
413
|
+
In the Controller case, it's same with the upper DTO story. With `nestia`, defining a generic typed controller class is also possible, too. By defining a generic typed controller class as a super-type class, you can reduce both duplicated code and description comments.
|
|
414
|
+
|
|
415
|
+
Look at the below code and feel how powerful `nestia` is. It should be stated that, `@nestjs/swagger` cannot construct such generic or union typed controller class.
|
|
416
|
+
|
|
417
|
+
- Simple [`CustomerSaleArticleCommentsController`](https://github.com/samchon/nestia/blob/master/demo/simple/src/controllers/ConsumerSaleArticleCommentsController.ts)
|
|
418
|
+
- Generic controllers
|
|
419
|
+
- abstract controller, [`SaleInquiriesController<Content, Store, Json>`](https://github.com/samchon/nestia/tree/master/demo/generic/src/controllers/SaleInquiriesController.ts)
|
|
420
|
+
- 1st sub-type controller, [`ConsumerSaleQuestionsController`](https://github.com/samchon/nestia/tree/master/demo/generic/src/controllers/ConsumerSaleQuestionsController.ts)
|
|
421
|
+
- 2nd sub-type controller, [`ConsumerSaleQuestionsController`](https://github.com/samchon/nestia/tree/master/demo/generic/src/controllers/ConsumerSaleQuestionsController.ts)
|
|
422
|
+
- Union controller, [`ConsumerSaleEntireArticlesController`](https://github.com/samchon/nestia/tree/master/demo/union/src/controllers/ConsumerSaleEntireArticlesController.ts)
|
|
423
|
+
|
|
424
|
+
> [typescript-is](https://github.com/woutervh-/typescript-is) can replace the class-validator with only one line.
|
|
425
|
+
>
|
|
426
|
+
> ```typescript
|
|
427
|
+
> import * as nest from "@nestjs/common";
|
|
428
|
+
> import { assertType } from "typescript-is";
|
|
429
|
+
>
|
|
430
|
+
> @nest.Controller("consumers/:section/sales/:saleId/questions")
|
|
431
|
+
> export class SaleQuestionsController
|
|
432
|
+
> extends SaleInquiriesController<
|
|
433
|
+
> ISaleQuestion,
|
|
434
|
+
> ISaleQuestion.IContent,
|
|
435
|
+
> ISaleQuestion.IStore>
|
|
436
|
+
> {
|
|
437
|
+
> public constructor()
|
|
438
|
+
> {
|
|
439
|
+
> super(input => assertType<ISaleQuestion.IStore>(input));
|
|
440
|
+
> }
|
|
441
|
+
> }
|
|
442
|
+
> ```
|
|
357
443
|
|
|
358
444
|
```typescript
|
|
359
|
-
|
|
360
|
-
|
|
445
|
+
import * as express from "express";
|
|
446
|
+
import * as nest from "@nestjs/common";
|
|
447
|
+
import helper from "nestia-helper";
|
|
448
|
+
|
|
449
|
+
import { ISaleInquiry } from "@api/structures/ISaleInquiry";
|
|
450
|
+
|
|
451
|
+
export abstract class SaleInquiriesController<
|
|
452
|
+
Content extends ISaleInquiry.IContent,
|
|
453
|
+
Store extends ISaleInquiry.IStore,
|
|
454
|
+
Json extends ISaleInquiry<Content>>
|
|
361
455
|
{
|
|
362
456
|
/**
|
|
363
|
-
*
|
|
457
|
+
* Constructor with type assert function.
|
|
458
|
+
*/
|
|
459
|
+
protected constructor(private readonly assert: (input: Store) => void);
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Store a new inquiry.
|
|
463
|
+
*
|
|
464
|
+
* Write a new article inquirying about a sale.
|
|
364
465
|
*
|
|
365
466
|
* @param request Instance of the Express.Request
|
|
366
467
|
* @param section Code of the target section
|
|
367
468
|
* @param saleId ID of the target sale
|
|
368
469
|
* @param input Content to archive
|
|
470
|
+
* @return Newly archived inquiry
|
|
369
471
|
*
|
|
370
|
-
* @return Newly archived question
|
|
371
472
|
* @throw 400 bad request error when type of the input data is not valid
|
|
372
473
|
* @throw 401 unauthorized error when you've not logged in yet
|
|
373
474
|
*/
|
|
@@ -375,40 +476,101 @@ export class ConsumerSaleQuestionsController
|
|
|
375
476
|
public store
|
|
376
477
|
(
|
|
377
478
|
@nest.Request() request: express.Request,
|
|
378
|
-
@
|
|
379
|
-
@
|
|
380
|
-
@nest.Body() input:
|
|
381
|
-
): Promise<
|
|
479
|
+
@helper.TypedParam("section", "string") section: string,
|
|
480
|
+
@helper.TypedParam("saleId", "string") saleId: string,
|
|
481
|
+
@nest.Body() input: Store
|
|
482
|
+
): Promise<Json>;
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Update an inquiry.
|
|
486
|
+
*
|
|
487
|
+
* Update ordinary inquiry article. However, it would not modify the content reocrd
|
|
488
|
+
* {@link ISaleInquiry.IContent}, but be accumulated into the {@link ISaleInquiry.contents}.
|
|
489
|
+
* Therefore, all of the poeple can read how the content has been changed.
|
|
490
|
+
*
|
|
491
|
+
* @param request Instance of the Express.Request
|
|
492
|
+
* @param section Code of the target section
|
|
493
|
+
* @param saleId ID of the target sale
|
|
494
|
+
* @param id ID of the target article to be updated
|
|
495
|
+
* @param input New content to be overwritten
|
|
496
|
+
* @return The newly created content record
|
|
497
|
+
*
|
|
498
|
+
* @throw 400 bad request error when type of the input data is not valid
|
|
499
|
+
* @throw 401 unauthorized error when you've not logged in yet
|
|
500
|
+
* @throw 403 forbidden error when the article is not yours
|
|
501
|
+
*/
|
|
502
|
+
@nest.Put(":id")
|
|
503
|
+
public update
|
|
504
|
+
(
|
|
505
|
+
@nest.Request() request: express.Request,
|
|
506
|
+
@helper.TypedParam("section", "string") section: string,
|
|
507
|
+
@helper.TypedParam("saleId", "string") saleId: string,
|
|
508
|
+
@helper.TypedParam("id", "number") id: number,
|
|
509
|
+
@nest.Body() input: Store
|
|
510
|
+
): Promise<Json>;
|
|
382
511
|
}
|
|
383
512
|
```
|
|
384
513
|
|
|
385
|
-
### SDK
|
|
386
|
-
When you run the [nestia](https://github.com/samchon/nestia) up using the upper controller class `ConsumerSaleQuestionsController`, the [nestia](https://github.com/samchon/nestia) would generate below function for the client developers, by analyzing the `ConsumerSaleQuestionsController` class in the compilation and runtime level.
|
|
387
514
|
|
|
388
|
-
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
### Software Development Kit
|
|
518
|
+
> `Swagger` is torturing client developers.
|
|
519
|
+
>
|
|
520
|
+
> If you're a backend developer and you deliver a `Swagger` to your companion client developers, they should analyze the `Swagger` and implement duplicated router functions with DTO interfaces by themselves. During those jobs, if a client developer takes a mistake by mis-reading the `Swagger`, it becomes a critical runtime error directly.
|
|
521
|
+
>
|
|
522
|
+
> Why are you torturing the client developers such like that? If you deliver an SDK (Software Development Kit) instead of the `Swagger`, the client developers don't need to read the `Swagger` file. They never need to implement the duplicated DTO interfaces with router functions, either.
|
|
523
|
+
>
|
|
524
|
+
> Therefore, just build the SDK through this `nestia` and deliver the SDK. Your client developers would be anticipated from the long time torturing and become happy. Your solution would be much more reliable and efficient, too.
|
|
525
|
+
|
|
526
|
+
Looking at the SDK library file, generated by `nestia`, it is perfect.
|
|
527
|
+
|
|
528
|
+
Route method, path and parameters are well-formed and DTO structures are correctly imported. Also, descriptive comments are fully revived in the SDK library, regardless of where they are written.
|
|
529
|
+
|
|
530
|
+
Furthermore, there's not any problem even when a generic typed controller class comes. `nestia` will specialize the generic arguments exactly, by analyzing your `NestJS` server code, in the compilation level.
|
|
531
|
+
|
|
532
|
+
- [simple/.../comments/index.ts](https://github.com/samchon/nestia/blob/master/demo/simple/src/api/functional/consumers/sales/articles/comments/index.ts)
|
|
533
|
+
- [generic/.../questions/index.ts](https://github.com/samchon/nestia/tree/master/demo/generic/src/api/functional/consumers/sales/questions/index.ts)
|
|
534
|
+
- [generic/.../reviews/index.ts](https://github.com/samchon/nestia/tree/master/demo/generic/src/api/functional/consumers/sales/reviews/index.ts)
|
|
535
|
+
- [union/.../entire_articles/index.ts](https://github.com/samchon/nestia/tree/master/demo/union/src/api/functional/consumers/sales/entire_articles/index.ts)
|
|
389
536
|
|
|
390
537
|
```typescript
|
|
391
538
|
/**
|
|
392
|
-
*
|
|
539
|
+
* @packageDocumentation
|
|
540
|
+
* @module api.functional.consumers.sales.reviews
|
|
541
|
+
* @nestia Generated by Nestia - https://github.com/samchon/nestia
|
|
542
|
+
*/
|
|
543
|
+
//================================================================
|
|
544
|
+
import { Fetcher, Primitive } from "nestia-fetcher";
|
|
545
|
+
import type { IConnection } from "nestia-fetcher";
|
|
546
|
+
import { createStringifier } from "typescript-json";
|
|
547
|
+
|
|
548
|
+
import type { ISaleReview } from "./../../../../structures/ISaleReview";
|
|
549
|
+
import type { ISaleInquiry } from "./../../../../structures/ISaleInquiry";
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Store a new inquiry.
|
|
553
|
+
*
|
|
554
|
+
* Write a new article inquirying about a sale.
|
|
393
555
|
*
|
|
394
556
|
* @param connection connection Information of the remote HTTP(s) server with headers (+encryption password)
|
|
395
557
|
* @param request Instance of the Express.Request
|
|
396
558
|
* @param section Code of the target section
|
|
397
559
|
* @param saleId ID of the target sale
|
|
398
560
|
* @param input Content to archive
|
|
399
|
-
* @return Newly archived
|
|
561
|
+
* @return Newly archived inquiry
|
|
400
562
|
* @throw 400 bad request error when type of the input data is not valid
|
|
401
563
|
* @throw 401 unauthorized error when you've not logged in yet
|
|
402
564
|
*
|
|
565
|
+
* @controller ConsumerSaleReviewsController.store()
|
|
566
|
+
* @path POST /consumers/:section/sales/:saleId/reviews
|
|
403
567
|
* @nestia Generated by Nestia - https://github.com/samchon/nestia
|
|
404
|
-
* @controller ConsumerSaleQuestionsController.store()
|
|
405
|
-
* @path POST /consumers/:section/sales/:saleId/questions/
|
|
406
568
|
*/
|
|
407
569
|
export function store
|
|
408
570
|
(
|
|
409
571
|
connection: IConnection,
|
|
410
572
|
section: string,
|
|
411
|
-
saleId:
|
|
573
|
+
saleId: string,
|
|
412
574
|
input: Primitive<store.Input>
|
|
413
575
|
): Promise<store.Output>
|
|
414
576
|
{
|
|
@@ -418,249 +580,304 @@ export function store
|
|
|
418
580
|
store.ENCRYPTED,
|
|
419
581
|
store.METHOD,
|
|
420
582
|
store.path(section, saleId),
|
|
421
|
-
input
|
|
583
|
+
input,
|
|
584
|
+
store.stringify
|
|
422
585
|
);
|
|
423
586
|
}
|
|
424
587
|
export namespace store
|
|
425
588
|
{
|
|
426
|
-
export type Input = Primitive<
|
|
427
|
-
export type Output = Primitive<ISaleInquiry<
|
|
589
|
+
export type Input = Primitive<ISaleReview.IStore>;
|
|
590
|
+
export type Output = Primitive<ISaleInquiry<ISaleReview.IContent>>;
|
|
428
591
|
|
|
429
592
|
export const METHOD = "POST" as const;
|
|
430
|
-
export const PATH: string = "/consumers/:section/sales/:saleId/
|
|
593
|
+
export const PATH: string = "/consumers/:section/sales/:saleId/reviews";
|
|
431
594
|
export const ENCRYPTED: Fetcher.IEncrypted = {
|
|
432
|
-
request:
|
|
433
|
-
response:
|
|
595
|
+
request: false,
|
|
596
|
+
response: false,
|
|
434
597
|
};
|
|
435
598
|
|
|
436
|
-
export function path(section: string, saleId:
|
|
599
|
+
export function path(section: string, saleId: string): string
|
|
437
600
|
{
|
|
438
|
-
return `/consumers/${section}/sales/${saleId}/
|
|
601
|
+
return `/consumers/${section}/sales/${saleId}/reviews`;
|
|
439
602
|
}
|
|
603
|
+
export const stringify = createStringifier<Input>();
|
|
440
604
|
}
|
|
441
|
-
```
|
|
442
605
|
|
|
443
|
-
|
|
444
|
-
|
|
606
|
+
/**
|
|
607
|
+
* Update an inquiry.
|
|
608
|
+
*
|
|
609
|
+
* Update ordinary inquiry article. However, it would not modify the content reocrd
|
|
610
|
+
* {@link ISaleInquiry.IContent}, but be accumulated into the {@link ISaleInquiry.contents}.
|
|
611
|
+
* Therefore, all of the poeple can read how the content has been changed.
|
|
612
|
+
*
|
|
613
|
+
* @param connection connection Information of the remote HTTP(s) server with headers (+encryption password)
|
|
614
|
+
* @param request Instance of the Express.Request
|
|
615
|
+
* @param section Code of the target section
|
|
616
|
+
* @param saleId ID of the target sale
|
|
617
|
+
* @param id ID of the target article to be updated
|
|
618
|
+
* @param input New content to be overwritten
|
|
619
|
+
* @return The newly created content record
|
|
620
|
+
* @throw 400 bad request error when type of the input data is not valid
|
|
621
|
+
* @throw 401 unauthorized error when you've not logged in yet
|
|
622
|
+
* @throw 403 forbidden error when the article is not yours
|
|
623
|
+
*
|
|
624
|
+
* @controller ConsumerSaleReviewsController.update()
|
|
625
|
+
* @path PUT /consumers/:section/sales/:saleId/reviews/:id
|
|
626
|
+
* @nestia Generated by Nestia - https://github.com/samchon/nestia
|
|
627
|
+
*/
|
|
628
|
+
export function update
|
|
629
|
+
(
|
|
630
|
+
connection: IConnection,
|
|
631
|
+
section: string,
|
|
632
|
+
saleId: string,
|
|
633
|
+
id: number,
|
|
634
|
+
input: Primitive<update.Input>
|
|
635
|
+
): Promise<update.Output>
|
|
636
|
+
{
|
|
637
|
+
return Fetcher.fetch
|
|
638
|
+
(
|
|
639
|
+
connection,
|
|
640
|
+
update.ENCRYPTED,
|
|
641
|
+
update.METHOD,
|
|
642
|
+
update.path(section, saleId, id),
|
|
643
|
+
input,
|
|
644
|
+
update.stringify
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
export namespace update
|
|
648
|
+
{
|
|
649
|
+
export type Input = Primitive<ISaleReview.IStore>;
|
|
650
|
+
export type Output = Primitive<ISaleInquiry<ISaleReview.IContent>>;
|
|
445
651
|
|
|
446
|
-
|
|
652
|
+
export const METHOD = "PUT" as const;
|
|
653
|
+
export const PATH: string = "/consumers/:section/sales/:saleId/reviews/:id";
|
|
654
|
+
export const ENCRYPTED: Fetcher.IEncrypted = {
|
|
655
|
+
request: false,
|
|
656
|
+
response: false,
|
|
657
|
+
};
|
|
447
658
|
|
|
448
|
-
|
|
449
|
-
{
|
|
450
|
-
|
|
451
|
-
"/consumers/{section}/sales/{saleId}/comments/{articleId}": {
|
|
452
|
-
"post": {
|
|
453
|
-
"tags": [],
|
|
454
|
-
"parameters": [
|
|
455
|
-
{
|
|
456
|
-
"name": "section",
|
|
457
|
-
"in": "path",
|
|
458
|
-
"description": "Code of the target section",
|
|
459
|
-
"schema": {
|
|
460
|
-
"type": "string",
|
|
461
|
-
"nullable": false
|
|
462
|
-
},
|
|
463
|
-
"required": true
|
|
464
|
-
},
|
|
465
|
-
{
|
|
466
|
-
"name": "saleId",
|
|
467
|
-
"in": "path",
|
|
468
|
-
"description": "ID of the target sale",
|
|
469
|
-
"schema": {
|
|
470
|
-
"type": "number",
|
|
471
|
-
"nullable": false
|
|
472
|
-
},
|
|
473
|
-
"required": true
|
|
474
|
-
},
|
|
475
|
-
{
|
|
476
|
-
"name": "articleId",
|
|
477
|
-
"in": "path",
|
|
478
|
-
"description": "ID of the target article",
|
|
479
|
-
"schema": {
|
|
480
|
-
"type": "number",
|
|
481
|
-
"nullable": false
|
|
482
|
-
},
|
|
483
|
-
"required": true
|
|
484
|
-
}
|
|
485
|
-
],
|
|
486
|
-
"requestBody": {
|
|
487
|
-
"description": "Content to write",
|
|
488
|
-
"content": {
|
|
489
|
-
"application/json": {
|
|
490
|
-
"schema": {
|
|
491
|
-
"$ref": "#/components/schemas/ISaleComment.IStore"
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
},
|
|
495
|
-
"required": true
|
|
496
|
-
},
|
|
497
|
-
"responses": {
|
|
498
|
-
"201": {
|
|
499
|
-
"description": "Newly archived comment",
|
|
500
|
-
"content": {
|
|
501
|
-
"application/json": {
|
|
502
|
-
"schema": {
|
|
503
|
-
"$ref": "#/components/schemas/ISaleComment"
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
},
|
|
508
|
-
"400": {
|
|
509
|
-
"description": "bad request error when type of the input data is not valid"
|
|
510
|
-
},
|
|
511
|
-
"401": {
|
|
512
|
-
"description": "unauthorized error when you've not logged in yet"
|
|
513
|
-
},
|
|
514
|
-
"403": {
|
|
515
|
-
"description": "forbidden error when you're a seller and the sale is not yours"
|
|
516
|
-
},
|
|
517
|
-
"404": {
|
|
518
|
-
"description": "not found error when unable to find the matched record"
|
|
519
|
-
}
|
|
520
|
-
},
|
|
521
|
-
"description": "Store a new comment."
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
},
|
|
525
|
-
"components": {
|
|
526
|
-
"schemas": {
|
|
527
|
-
"ISaleComment": {
|
|
528
|
-
"type": "object",
|
|
529
|
-
"properties": {
|
|
530
|
-
"id": {
|
|
531
|
-
"description": "Primary Key.",
|
|
532
|
-
"type": "number",
|
|
533
|
-
"nullable": false
|
|
534
|
-
},
|
|
535
|
-
"writer_type": {
|
|
536
|
-
"description": "Type of the writer.",
|
|
537
|
-
"type": "string",
|
|
538
|
-
"nullable": false
|
|
539
|
-
},
|
|
540
|
-
"writer_name": {
|
|
541
|
-
"description": "Name of the writer.",
|
|
542
|
-
"type": "string",
|
|
543
|
-
"nullable": false
|
|
544
|
-
},
|
|
545
|
-
"contents": {
|
|
546
|
-
"description": "Contents of the comments.\n\nWhen the comment writer tries to modify content, it would not modify the comment\ncontent but would be accumulated. Therefore, all of the people can read how\nthe content has been changed.",
|
|
547
|
-
"type": "array",
|
|
548
|
-
"items": {
|
|
549
|
-
"$ref": "#/components/schemas/ISaleComment.IContent"
|
|
550
|
-
},
|
|
551
|
-
"nullable": false
|
|
552
|
-
},
|
|
553
|
-
"created_at": {
|
|
554
|
-
"description": "Creation time.",
|
|
555
|
-
"type": "string",
|
|
556
|
-
"nullable": false
|
|
557
|
-
}
|
|
558
|
-
},
|
|
559
|
-
"nullable": false,
|
|
560
|
-
"required": [
|
|
561
|
-
"id",
|
|
562
|
-
"writer_type",
|
|
563
|
-
"writer_name",
|
|
564
|
-
"contents",
|
|
565
|
-
"created_at"
|
|
566
|
-
],
|
|
567
|
-
"description": "Comment wrote on an article."
|
|
568
|
-
},
|
|
569
|
-
"ISaleComment.IContent": {
|
|
570
|
-
"type": "object",
|
|
571
|
-
"properties": {
|
|
572
|
-
"created_at": {
|
|
573
|
-
"description": "Creation time.",
|
|
574
|
-
"type": "string",
|
|
575
|
-
"nullable": false
|
|
576
|
-
},
|
|
577
|
-
"body": {
|
|
578
|
-
"description": "Body of the content.",
|
|
579
|
-
"type": "string",
|
|
580
|
-
"nullable": false
|
|
581
|
-
}
|
|
582
|
-
},
|
|
583
|
-
"nullable": false,
|
|
584
|
-
"required": [
|
|
585
|
-
"created_at",
|
|
586
|
-
"body"
|
|
587
|
-
],
|
|
588
|
-
"description": "Content info."
|
|
589
|
-
},
|
|
590
|
-
"ISaleComment.IStore": {
|
|
591
|
-
"type": "object",
|
|
592
|
-
"properties": {
|
|
593
|
-
"body": {
|
|
594
|
-
"description": "Body of the content.",
|
|
595
|
-
"type": "string",
|
|
596
|
-
"nullable": false
|
|
597
|
-
}
|
|
598
|
-
},
|
|
599
|
-
"nullable": false,
|
|
600
|
-
"required": [
|
|
601
|
-
"body"
|
|
602
|
-
],
|
|
603
|
-
"description": "Store info."
|
|
604
|
-
}
|
|
659
|
+
export function path(section: string, saleId: string, id: number): string
|
|
660
|
+
{
|
|
661
|
+
return `/consumers/${section}/sales/${saleId}/reviews/${id}`;
|
|
605
662
|
}
|
|
606
|
-
|
|
663
|
+
export const stringify = createStringifier<Input>();
|
|
607
664
|
}
|
|
608
665
|
```
|
|
609
666
|
|
|
610
667
|
|
|
611
668
|
|
|
612
669
|
|
|
670
|
+
### Swagger
|
|
671
|
+
Building `Swagger` is also possible and even much powerful.
|
|
613
672
|
|
|
614
|
-
|
|
615
|
-
### Template Project
|
|
616
|
-
https://github.com/samchon/backend
|
|
673
|
+
Looking at the [simple/swagger.json](https://editor.swagger.io/?url=https%3A%2F%2Fraw.githubusercontent.com%2Fsamchon%2Fnestia%2Fmaster%2Fdemo%2Fsimple%2Fswagger.json) file, generated by `nestia`, everything is perfect. Route method, path and parameters are well-formed. Also, schema definitions are exactly matched with the pure interface type `ISaleArticleComment`. Of course, descriptive comments are perfectly resurrected in the `description` properties of the `swagger.json` file.
|
|
617
674
|
|
|
618
|
-
|
|
675
|
+
Looking at the another file [generic/swagger.json](https://editor.swagger.io/?url=https%3A%2F%2Fraw.githubusercontent.com%2Fsamchon%2Fnestia%2Fmaster%2Fdemo%2Fgeneric%2Fswagger.json), you can find that there isn't any problem even when a generic typed DTO and controller come. The last file [union/swagger.json](https://editor.swagger.io/?url=https%3A%2F%2Fraw.githubusercontent.com%2Fsamchon%2Fnestia%2Fmaster%2Fdemo%2Funion%2Fswagger.json), there's no problem on the union type, either.
|
|
619
676
|
|
|
620
|
-
|
|
677
|
+
- View in the `Swagger Editor`
|
|
678
|
+
- [simple/swagger.json](https://editor.swagger.io/?url=https%3A%2F%2Fraw.githubusercontent.com%2Fsamchon%2Fnestia%2Fmaster%2Fdemo%2Fsimple%2Fswagger.json)
|
|
679
|
+
- [generic/swagger.json](https://editor.swagger.io/?url=https%3A%2F%2Fraw.githubusercontent.com%2Fsamchon%2Fnestia%2Fmaster%2Fdemo%2Fgeneric%2Fswagger.json)
|
|
680
|
+
- [union/swagger.json](https://editor.swagger.io/?url=https%3A%2F%2Fraw.githubusercontent.com%2Fsamchon%2Fnestia%2Fmaster%2Fdemo%2Funion%2Fswagger.json)
|
|
621
681
|
|
|
622
|
-
|
|
682
|
+

|
|
623
683
|
|
|
624
|
-
### Nestia-Helper
|
|
625
|
-
https://github.com/samchon/nestia-helper
|
|
626
684
|
|
|
627
|
-
Helper library of the `NestJS` with [nestia](https://github.com/samchon/nestia).
|
|
628
685
|
|
|
629
|
-
[nestia-helper](https://github.com/samchon/nestia-helper) is a type of helper library for `Nestia` by enhancing decorator functions. Also, all of the decorator functions provided by this [nestia-helper](https://github.com/samchon/nestia-helper) are all fully compatible with the [nestia](https://github.com/samchon/nestia), who can generate SDK library by analyzing NestJS controller classes in the compilation level.
|
|
630
686
|
|
|
631
|
-
|
|
687
|
+
## Configuration
|
|
688
|
+
Components | `nestia.config.ts` | `CLI` | `@nestjs/swagger`
|
|
689
|
+
-----------------------------|--------------------|-------|------------------
|
|
690
|
+
Swagger Generation | ✔ | ✔ | ✔
|
|
691
|
+
SDK Generation | ✔ | ✔ | ❌
|
|
692
|
+
2x faster `JSON.stringify()` | ✔ | ❌ | ❌
|
|
693
|
+
Type check in runtime | ✔ | ❌ | ❌
|
|
694
|
+
Custom compiler options | ✔ | ❌ | ❌
|
|
632
695
|
|
|
633
|
-
|
|
634
|
-
- [EncryptedController](https://github.com/samchon/nestia-helper#encryptedcontroller), [EncryptedModule](https://github.com/samchon/nestia-helper#encryptedmodule)
|
|
635
|
-
- [TypedRoute](https://github.com/samchon/nestia-helper#typedroute), [EncryptedRoute](https://github.com/samchon/nestia-helper#encryptedroute)
|
|
636
|
-
- [TypedParam](https://github.com/samchon/nestia-helper#typedparam), [EncryptedBody](https://github.com/samchon/nestia-helper#encryptedbody), [PlainBody](https://github.com/samchon/nestia-helper#plainbody)
|
|
637
|
-
- [ExceptionManager](https://github.com/samchon/nestia-helper#exceptionmanager)
|
|
696
|
+
`nestia` can configure generator options by two ways: CLI and configuration file.
|
|
638
697
|
|
|
639
|
-
|
|
640
|
-
https://github.com/samchon/safe-typeorm
|
|
698
|
+
At first, the CLI (Command Line Interface) is convenient, but does not support detailed options.
|
|
641
699
|
|
|
642
|
-
|
|
700
|
+
```sh
|
|
701
|
+
# BASIC COMMAND
|
|
702
|
+
npx nestia <sdk|swagger> <source_directories_or_patterns> \
|
|
703
|
+
--exclude <exclude_directory_or_pattern> \
|
|
704
|
+
--out <output_directory_or_file>
|
|
705
|
+
|
|
706
|
+
# EXAMPLES
|
|
707
|
+
npx nestia sdk "src/controllers" --out "src/api"
|
|
708
|
+
npx nestia swagger "src/**/*.controller.ts" --out "swagger.json"
|
|
709
|
+
npx nestia swagger "src/main/controllers" "src/sub/controllers" \
|
|
710
|
+
--exclude "src/main/test" \
|
|
711
|
+
--out "composite.swagger.json"
|
|
712
|
+
|
|
713
|
+
# ONLY WHEN NESTIA.CONFIG.TS EXISTS
|
|
714
|
+
npx nestia sdk
|
|
715
|
+
npx nestia swagger
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
Besides, the configuration file `nestia.config.ts` supports much detailed options.
|
|
719
|
+
|
|
720
|
+
The detailed options are listed up to the `IConfiguration` interface. You can utilize the `IConfiguration` type like below. If you want to know more about those options, please check the [Guide Documents](https://github.com/samchon/nestia/wiki/Configuration).
|
|
721
|
+
|
|
722
|
+
<details>
|
|
723
|
+
<summary> Read <code>IConfiguration</code> </summary>
|
|
724
|
+
|
|
725
|
+
```typescript
|
|
726
|
+
/**
|
|
727
|
+
* Definition for the `nestia.config.ts` file.
|
|
728
|
+
*
|
|
729
|
+
* @author Jeongho Nam - https://github.com/samchon
|
|
730
|
+
*/
|
|
731
|
+
export interface IConfiguration {
|
|
732
|
+
/**
|
|
733
|
+
* List of files or directories containing the `NestJS` controller classes.
|
|
734
|
+
*/
|
|
735
|
+
input: string | string[] | IConfiguration.IInput;
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Output directory that SDK would be placed in.
|
|
739
|
+
*
|
|
740
|
+
* If not configured, you can't build the SDK library.
|
|
741
|
+
*/
|
|
742
|
+
output?: string;
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* Compiler options for the TypeScript.
|
|
746
|
+
*
|
|
747
|
+
* If you've omitted this property or the assigned property cannot fully cover the
|
|
748
|
+
* `tsconfig.json`, the properties from the `tsconfig.json` would be assigned to here.
|
|
749
|
+
* Otherwise, this property has been configured and it's detailed values are different
|
|
750
|
+
* with the `tsconfig.json`, this property values would be overwritten.
|
|
751
|
+
*
|
|
752
|
+
* ```typescript
|
|
753
|
+
* import ts from "typescript";
|
|
754
|
+
*
|
|
755
|
+
* const tsconfig: ts.TsConfig;
|
|
756
|
+
* const nestiaConfig: IConfiguration;
|
|
757
|
+
*
|
|
758
|
+
* const compilerOptions: ts.CompilerOptions = {
|
|
759
|
+
* ...tsconfig.compilerOptions,
|
|
760
|
+
* ...(nestiaConfig.compilerOptions || {})
|
|
761
|
+
* }
|
|
762
|
+
* ```
|
|
763
|
+
*/
|
|
764
|
+
compilerOptions?: ts.CompilerOptions;
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Whether to assert parameter types or not.
|
|
768
|
+
*
|
|
769
|
+
* If you configure this property to be `true`, all of the function parameters would be
|
|
770
|
+
* checked through the [typescript-is](https://github.com/woutervh-/typescript-is). This
|
|
771
|
+
* option would make your SDK library slower, but would be much safer in the type level
|
|
772
|
+
* even in the runtime environment.
|
|
773
|
+
*/
|
|
774
|
+
assert?: boolean;
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Whether to optimize JSON string conversion 2x faster or not.
|
|
778
|
+
*
|
|
779
|
+
* If you configure this property to be `true`, the SDK library would utilize the
|
|
780
|
+
* [typescript-json](https://github.com/samchon/typescript-json) and the JSON string
|
|
781
|
+
* conversion speed really be 2x faster.
|
|
782
|
+
*/
|
|
783
|
+
json?: boolean;
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Building `swagger.json` is also possible.
|
|
787
|
+
*
|
|
788
|
+
* If not specified, you can't build the `swagger.json`.
|
|
789
|
+
*/
|
|
790
|
+
swagger?: IConfiguration.ISwagger;
|
|
791
|
+
}
|
|
792
|
+
export namespace IConfiguration
|
|
793
|
+
{
|
|
794
|
+
/**
|
|
795
|
+
* List of files or directories to include or exclude to specifying the `NestJS`
|
|
796
|
+
* controllers.
|
|
797
|
+
*/
|
|
798
|
+
export interface IInput {
|
|
799
|
+
/**
|
|
800
|
+
* List of files or directories containing the `NestJS` controller classes.
|
|
801
|
+
*/
|
|
802
|
+
include: string[];
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* List of files or directories to be excluded.
|
|
806
|
+
*/
|
|
807
|
+
exclude?: string[];
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Building `swagger.json` is also possible.
|
|
812
|
+
*/
|
|
813
|
+
export interface ISwagger {
|
|
814
|
+
/**
|
|
815
|
+
* Output path of the `swagger.json`.
|
|
816
|
+
*
|
|
817
|
+
* If you've configured only directory, the file name would be the `swagger.json`.
|
|
818
|
+
* Otherwise you've configured the full path with file name and extension, the
|
|
819
|
+
* `swagger.json` file would be renamed to it.
|
|
820
|
+
*/
|
|
821
|
+
output: string;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
```
|
|
825
|
+
</details>
|
|
826
|
+
|
|
827
|
+
```typescript
|
|
828
|
+
import type { IConfiguration } from "nestia";
|
|
829
|
+
|
|
830
|
+
export const NESTIA_CONFIG: IConfiguration = {
|
|
831
|
+
input: "./src/controllers",
|
|
832
|
+
output: "./src/api",
|
|
833
|
+
json: true,
|
|
834
|
+
swagger: {
|
|
835
|
+
output: "./public/swagger.json"
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
export default NESTIA_CONFIG;
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
|
|
844
|
+
## Appendix
|
|
845
|
+
### Dependencies of the SDK
|
|
846
|
+
An SDK library generated by `nestia` requires [nestia-fetcher](https://github.com/samchon/nestia-fetcher) module. Also, [typescript-is](https://github.com/woutervh-/typescript-is) and [typescript-json](https://github.com/samchon/typescript-json) modules can be required following your `nestia.config.ts` configuration file.
|
|
847
|
+
|
|
848
|
+
The `npx nestia install` command installs those dependencies with the `package.json` configuration.
|
|
849
|
+
|
|
850
|
+
```bash
|
|
851
|
+
# MOVE TO THE DISTRIBUTION DIRECTORY
|
|
852
|
+
cd packages/api
|
|
853
|
+
|
|
854
|
+
# INSTALL DEPENDENCIES OF THE SDK
|
|
855
|
+
npx nestia install
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
### Template Repository
|
|
859
|
+
https://github.com/samchon/backend
|
|
643
860
|
|
|
644
|
-
|
|
861
|
+
I support template backend project using this `nestia` library, `samchon/backend`.
|
|
645
862
|
|
|
646
|
-
|
|
647
|
-
- Errors would be detected in the **compilation** level
|
|
648
|
-
- **Auto Completion** would be provided
|
|
649
|
-
- **Type Hint** would be supported
|
|
650
|
-
- You can implement [**App-join**](https://github.com/samchon/safe-typeorm#app-join-builder) very conveniently
|
|
651
|
-
- When [**SELECT**ing for **JSON** conversion](https://github.com/samchon/safe-typeorm#json-select-builder)
|
|
652
|
-
- [**App-Join**](https://github.com/samchon/safe-typeorm#app-join-builder) with the related entities would be automatically done
|
|
653
|
-
- Exact JSON **type** would be automatically **deduced**
|
|
654
|
-
- The **performance** would be **automatically tuned**
|
|
655
|
-
- When [**INSERT**](https://github.com/samchon/safe-typeorm#insert-collection)ing records
|
|
656
|
-
- Sequence of tables would be automatically sorted by analyzing dependencies
|
|
657
|
-
- The **performance** would be **automatically tuned**
|
|
863
|
+
Reading the README content of the backend template repository, you can find lots of example backend projects who've been generated from the backend. Furthermore, those example projects guide how to generate SDK library from `nestia` and how to distribute the SDK library thorugh the NPM module.
|
|
658
864
|
|
|
659
|
-
|
|
865
|
+
Therefore, if you're planning to compose your own backend project using this `nestia`, I recommend you to create the repository and learn from the `samchon/backend` template project.
|
|
660
866
|
|
|
661
867
|
### Archidraw
|
|
662
868
|
https://www.archisketch.com/
|
|
663
869
|
|
|
664
870
|
I have special thanks to the Archidraw, where I'm working for.
|
|
665
871
|
|
|
666
|
-
The Archidraw is a great IT company developing 3D interior editor and lots of solutions based on the 3D assets. Also, the Archidraw is the first company who had adopted this
|
|
872
|
+
The Archidraw is a great IT company developing 3D interior editor and lots of solutions based on the 3D assets. Also, the Archidraw is the first company who had adopted this nestia on their commercial backend project, even this nestia was in the alpha level.
|
|
873
|
+
|
|
874
|
+
> 저희 회사 "아키드로우" 에서, 삼촌과 함께 일할 프론트 개발자 분들을, 최고의 대우로 모십니다.
|
|
875
|
+
>
|
|
876
|
+
> "아키드로우" 는 3D (인테리어) 에디터 및 이에 관한 파생 솔루션들을 만드는 회사입니다. 다만 저희 회사의 주력 제품이 3D 에디터라 하여, 반드시 3D 내지 랜더링에 능숙해야 하는 것은 아니니, 일반적인 프론트 개발자 분들도 망설임없이 지원해주십시오.
|
|
877
|
+
>
|
|
878
|
+
> 그리고 저희 회사는 분위기가 다들 친하고 즐겁게 지내는 분위기입니다. 더하여 위 `nestia` 나 [typescript-json](https://github.com/samchon/typescript-json) 및 [payments](https://github.com/archidraw/payments) 등, 제법 합리적(?)이고 재미난 프로젝트들을 다양하게 체험해보실 수 있습니다.
|
|
879
|
+
>
|
|
880
|
+
> - 회사소개서: [archidraw.pdf](https://github.com/archidraw/payments/files/7696710/archidraw.pdf)
|
|
881
|
+
> - 기술 스택: React + TypeScript
|
|
882
|
+
> - 이력서: 자유 양식
|
|
883
|
+
> - 지원처: samchon@archisketch.com
|