@simitgroup/simpleapp-generator 1.0.21 → 1.0.23
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 copy.md +882 -0
- package/README.md +53 -824
- package/definations/category.cat.jsonschema.json +11 -13
- package/definations/level.lvl.jsonschema.json +48 -0
- package/definations/product.prd.jsonschema.json +8 -2
- package/dist/framework.js +42 -23
- package/dist/framework.js.map +1 -1
- package/dist/generate.js +3 -3
- package/dist/generate.js.map +1 -1
- package/dist/index.js +8 -7
- package/dist/index.js.map +1 -1
- package/openapitools.json +7 -0
- package/package.json +1 -1
- package/sampleconfig.json +3 -0
- package/src/framework.ts +37 -19
- package/src/generate.ts +3 -3
- package/src/index.ts +8 -7
- package/templates/nest/nest.env.eta +7 -0
- package/templates/{nest.main.eta → nest/nest.main.eta} +1 -1
- package/templates/nuxt/env.eta +5 -3
- package/backend1/.env +0 -5
- package/backend1/.eslintrc.js +0 -25
- package/backend1/.prettierrc +0 -4
- package/backend1/README.md +0 -73
- package/backend1/nest-cli.json +0 -8
- package/backend1/package.json +0 -75
- package/backend1/pnpm-lock.yaml +0 -5459
- package/backend1/src/app.controller.js +0 -71
- package/backend1/src/app.controller.js.map +0 -1
- package/backend1/src/app.controller.spec.js +0 -21
- package/backend1/src/app.controller.spec.js.map +0 -1
- package/backend1/src/app.controller.spec.ts +0 -22
- package/backend1/src/app.controller.ts +0 -12
- package/backend1/src/app.module.js +0 -67
- package/backend1/src/app.module.js.map +0 -1
- package/backend1/src/app.module.ts +0 -10
- package/backend1/src/app.service.js +0 -64
- package/backend1/src/app.service.js.map +0 -1
- package/backend1/src/app.service.ts +0 -8
- package/backend1/src/class/SimpleAppController.js +0 -38
- package/backend1/src/class/SimpleAppController.js.map +0 -1
- package/backend1/src/class/SimpleAppController.ts +0 -69
- package/backend1/src/class/SimpleAppService.js +0 -264
- package/backend1/src/class/SimpleAppService.js.map +0 -1
- package/backend1/src/class/SimpleAppService.ts +0 -213
- package/backend1/src/main.js +0 -22
- package/backend1/src/main.js.map +0 -1
- package/backend1/src/main.ts +0 -20
- package/backend1/test/app.e2e-spec.js +0 -45
- package/backend1/test/app.e2e-spec.js.map +0 -1
- package/backend1/test/app.e2e-spec.ts +0 -24
- package/backend1/test/jest-e2e.json +0 -9
- package/backend1/tsconfig.build.json +0 -4
- package/backend1/tsconfig.json +0 -1
- package/frontend1/README.md +0 -63
- package/frontend1/app.vue +0 -8
- package/frontend1/assets/css/tailwind.css +0 -28
- package/frontend1/components/CrudSimple.vue +0 -112
- package/frontend1/components/DebugDocumentData.vue +0 -20
- package/frontend1/components/EventMonitor.vue +0 -79
- package/frontend1/components/Menus.vue +0 -18
- package/frontend1/layouts/default.vue +0 -10
- package/frontend1/nuxt.config.js +0 -42
- package/frontend1/nuxt.config.js.map +0 -1
- package/frontend1/nuxt.config.ts +0 -42
- package/frontend1/package-lock.json +0 -11877
- package/frontend1/package.json +0 -38
- package/frontend1/pages/index.vue +0 -3
- package/frontend1/plugins/simpleapp.js +0 -73
- package/frontend1/plugins/simpleapp.js.map +0 -1
- package/frontend1/plugins/simpleapp.ts +0 -73
- package/frontend1/pnpm-lock.yaml +0 -8339
- package/frontend1/public/favicon.ico +0 -0
- package/frontend1/server/api/[...].js +0 -117
- package/frontend1/server/api/[...].js.map +0 -1
- package/frontend1/server/api/[...].ts +0 -131
- package/frontend1/server/tsconfig.json +0 -3
- package/frontend1/tailwind.config.js +0 -10
- package/frontend1/tailwind.config.js.map +0 -1
- package/frontend1/tailwind.config.ts +0 -9
- package/frontend1/tsconfig.json +0 -4
- package/src/installdependency.ts +0 -4
- package/templates/SimpleAppClient.eta +0 -116
- package/templates/app.vue.eta +0 -21
- package/templates/nest.env.eta +0 -5
- /package/src/{index2.ts → index2.ts-old} +0 -0
- /package/templates/{SimpleAppController.eta → nest/SimpleAppController.eta} +0 -0
- /package/templates/{SimpleAppService.eta → nest/SimpleAppService.eta} +0 -0
- /package/templates/{app.module.eta → nest/app.module.eta} +0 -0
package/README copy.md
ADDED
|
@@ -0,0 +1,882 @@
|
|
|
1
|
+
# Quick start
|
|
2
|
+
1. git clone from simpleapp-generator
|
|
3
|
+
```sh
|
|
4
|
+
git clone https://github.com/SIMITGROUP/simpleapp-generator-template myapp
|
|
5
|
+
cd ~/myapp
|
|
6
|
+
simpleapp-generator -c config.json
|
|
7
|
+
```
|
|
8
|
+
2. start backend
|
|
9
|
+
```sh
|
|
10
|
+
cd ~/myapp/backend
|
|
11
|
+
pnpm start:dev
|
|
12
|
+
```
|
|
13
|
+
3. start frontend
|
|
14
|
+
```sh
|
|
15
|
+
cd ~/myapp/frontend
|
|
16
|
+
pnpm dev
|
|
17
|
+
```
|
|
18
|
+
4. try ui:
|
|
19
|
+
* frontend: (http://localhost:8080)[http://localhost:8080]
|
|
20
|
+
* backend: (http://localhost:8000/api)[http://localhost:8000/api]
|
|
21
|
+
5. Match the json schema and the generated forms
|
|
22
|
+
```sh
|
|
23
|
+
code ~/mydoc
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
# Concept of Development
|
|
27
|
+
Development using simpleapp-generator involve below steps:
|
|
28
|
+
[Simple]
|
|
29
|
+
1. create appropriate jsonschema
|
|
30
|
+
2. generate frontend and backend architectures
|
|
31
|
+
3. start backend service, obtain and save api definations into openapi.yaml
|
|
32
|
+
4. regenerate codes so frontend can obtain openapi clients
|
|
33
|
+
5. align frontend UI, add necessary component such as css and ui components
|
|
34
|
+
|
|
35
|
+
[Advance]
|
|
36
|
+
1. complete simple task
|
|
37
|
+
2. add more api/process at backend `controller`,`service`,`schema`. Such as:
|
|
38
|
+
a. special search
|
|
39
|
+
b. special workflows
|
|
40
|
+
c. connect external api
|
|
41
|
+
d. additional data processing and validation which is not supported by jsonschema (AJV)
|
|
42
|
+
3. security like sso/jwt, plugins
|
|
43
|
+
a. keycloak integration at frontends
|
|
44
|
+
b. backend manage jwt
|
|
45
|
+
4. allow additional field formats, validations by modifying ajv
|
|
46
|
+
a. allow custom jsonschema field property, and do something at backend
|
|
47
|
+
b. allow custom field format, and do something at backend
|
|
48
|
+
5. repeat same typscript formula at frontend and backend
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
after generate
|
|
52
|
+
1. `./backend/tsconfig.ts` add bolow into compile options
|
|
53
|
+
```typescript
|
|
54
|
+
"resolveJsonModule": true,
|
|
55
|
+
"esModuleInterop": true,
|
|
56
|
+
```
|
|
57
|
+
2.`./backend/.env` change mongodb setting as below example:
|
|
58
|
+
```bash
|
|
59
|
+
MONGODB_URL='mongodb://mongoadmin:secret@localhost:27017/admin?authMechanism=DEFAULT'
|
|
60
|
+
```
|
|
61
|
+
3. download http://localhost:8080/api into `./openapi.yaml`
|
|
62
|
+
4. regenerate code (for frontend can function completely)
|
|
63
|
+
5.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
1. install openapi-generator, pnpm, nest, rename openapi for new setup
|
|
67
|
+
2. load backend tsconfig and add more property: **
|
|
68
|
+
3. add prettier formating option for frontend
|
|
69
|
+
4. error messages
|
|
70
|
+
5. fix single and multi select bugs
|
|
71
|
+
6. function of remain menulist
|
|
72
|
+
7. security of string input, block xss
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
errors formating
|
|
76
|
+
18.keep audit trail into db
|
|
77
|
+
10.add backend find options
|
|
78
|
+
10.add frontend find options
|
|
79
|
+
11.retain modifications of controller, service, apiclients
|
|
80
|
+
14.add permission control
|
|
81
|
+
16.access right
|
|
82
|
+
17.setting of tenants
|
|
83
|
+
|
|
84
|
+
authentication in nuxt
|
|
85
|
+
jwt in backend
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
9. beautify default tailwind ui
|
|
89
|
+
1. front page
|
|
90
|
+
2. top bar
|
|
91
|
+
3. menu bars
|
|
92
|
+
4. default with of each component is it nicely fit
|
|
93
|
+
5. table layout
|
|
94
|
+
7. error formating
|
|
95
|
+
9. write proper user guide
|
|
96
|
+
13.add workflow functions
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
hold
|
|
101
|
+
|
|
102
|
+
10.plugin for ajv
|
|
103
|
+
long string format for description
|
|
104
|
+
|
|
105
|
+
# Todo
|
|
106
|
+
x21.control csrf
|
|
107
|
+
x8. simpleapp generate currentfolder error **
|
|
108
|
+
x1. override app.vue *
|
|
109
|
+
x2. create layout
|
|
110
|
+
simpleapp (first time only)
|
|
111
|
+
/default *
|
|
112
|
+
x3. components/ (first time only)
|
|
113
|
+
x /MonitorEvent.vue *
|
|
114
|
+
x /CrudBasic.vue **
|
|
115
|
+
x /Menubar *
|
|
116
|
+
4. create page/docs (everytime)
|
|
117
|
+
/index.ts
|
|
118
|
+
//create page if docs/documentname not exists ***
|
|
119
|
+
//override if docs/documentname/delete-me-for-avoid-override exists *
|
|
120
|
+
5. login/logout sessions
|
|
121
|
+
x6. auto create *
|
|
122
|
+
x server/api to backend *
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
1. define foreign key relationship in json schema2
|
|
129
|
+
2. auto index and block deletion
|
|
130
|
+
3. when delete identify foreign connected documents
|
|
131
|
+
4. how to unique key
|
|
132
|
+
5. how to multi-tenancy
|
|
133
|
+
6. login/logout in nuxt
|
|
134
|
+
7. jwt in nestjs
|
|
135
|
+
8. format errors at server side link back client side
|
|
136
|
+
9. how to auto toast
|
|
137
|
+
10.server side custom validation link back client side
|
|
138
|
+
11.permission controls
|
|
139
|
+
12.find records
|
|
140
|
+
13.audit trail
|
|
141
|
+
14.data isolation by org, branch and tenant
|
|
142
|
+
15.statistics, aggregations
|
|
143
|
+
16.auto generate frontend page
|
|
144
|
+
17.
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# simpleapp-generator
|
|
151
|
+
## this project still in alpha stage!
|
|
152
|
+
|
|
153
|
+
SimpleApp is an frontend and backend code generator, the ideal of this project is to allow developer build reliable and scalable application with low code methods.
|
|
154
|
+
|
|
155
|
+
It suitable for complex schema +complex calculation such as:
|
|
156
|
+
1. sales invoice: having parent and childs as 1 document, it need to calculate tax, discount, exchange rate
|
|
157
|
+
2. delivery order: need to calculate total quantity, unit of measurement conversion
|
|
158
|
+
|
|
159
|
+
Key Ideal:
|
|
160
|
+
1. Every data store as json format, name as `document`
|
|
161
|
+
2. Every document defined by jsonschema, and store in folder `definations`
|
|
162
|
+
3. We store jsonschema as `<uniquedocumentname>.<uniquedocumentshortname>.jsonschema.json`. Example: `purchaseorder.po.jsonschema.json`, `student.std.jsonschema.json`
|
|
163
|
+
4. `JsonSchema` used to generate:
|
|
164
|
+
- multiple pattern of data types for database, dto, frontend, backend. The data type match to `jsonschema`
|
|
165
|
+
- api controller (openapi)
|
|
166
|
+
- simpleapp frontend and backend objects
|
|
167
|
+
5. Generated code will control data validation in both frontend and backend using `ajv`
|
|
168
|
+
6. There is few important keyword need to know:
|
|
169
|
+
- `jsondata`: actual data like `{"document_no":"PO001",amount:300}`
|
|
170
|
+
- `jsonschema`: it is schema of `jsondata`, we use it to generate CRUD codes
|
|
171
|
+
- `frontend`: user interface framework using nuxt (vue+typescript), it doesn't store any data
|
|
172
|
+
- `backend`: api server using nest(typescript), it provide openapi, and store data into mongodb
|
|
173
|
+
- `doc service`: a typescript class use for process specific document in server. example" `po.service.ts`
|
|
174
|
+
- `doc controller`: it is api router for route http traffic to document service. example: `po.controller.ts`
|
|
175
|
+
- `doc client`: frontend client, it provide reactive data and data processing mechanism for frontend
|
|
176
|
+
|
|
177
|
+
6. To make our app useful, we perform development at
|
|
178
|
+
- backend: modify `api controller` and `backend document service`
|
|
179
|
+
- frontend: layout user interface, bind input fields to `doc client` , and modify `doc client` required
|
|
180
|
+
7. We may frequently change `jsonschema`, `doc service`, `doc controller`, `doc client`:
|
|
181
|
+
- the previous modified code remain when you regenerate code (with specific rules)
|
|
182
|
+
8. After regenerate codes, some data processing codes in `doc service` will sync into `doc client`, to reduce repeat coding at both end
|
|
183
|
+
|
|
184
|
+
## Benefit
|
|
185
|
+
- Use `jsonschema` generate most of the frontend and backend code
|
|
186
|
+
- Generated frontend and backend code in typescript+OOP.
|
|
187
|
+
- it control as tight as possible the frontend and backend data consistency
|
|
188
|
+
- support complex data schema, included parent and childs, nested objects
|
|
189
|
+
- enforce frontend and backend use same data type
|
|
190
|
+
- data store in mongodb, exactly same with schema, no join no headache
|
|
191
|
+
- flexible frontend, you can code react or vue, no problem. `simpleapp generator` only focus data, not ui
|
|
192
|
+
- allow developer enforce specific data processing in frontend and backend
|
|
193
|
+
- you can regenerate source code multiple time without worry your customization gone (there is a way!)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
Init Nuxt script
|
|
197
|
+
1. npm i -D @sidebase/nuxt-auth
|
|
198
|
+
2. pnpm i --save next-auth@4.21.1
|
|
199
|
+
npm i -D @sidebase/nuxt-session
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
## You shall know
|
|
204
|
+
This project assume you familiar with below:
|
|
205
|
+
1. typescript (no typescript, not reliable frontend)
|
|
206
|
+
2. mongodb
|
|
207
|
+
3. vue/react kind of ecosystem
|
|
208
|
+
|
|
209
|
+
# Special Format:
|
|
210
|
+
There is special format value:
|
|
211
|
+
1. `field-autcomplete-code`:field for document code, like `student_code,document_no`
|
|
212
|
+
2. `field-autocomplete-label`: field for document name, like `student_name, product_name`
|
|
213
|
+
|
|
214
|
+
# Special properties:
|
|
215
|
+
## object:
|
|
216
|
+
* autocomplete-src=category => autocomplete list from server-url/category/autocomplete
|
|
217
|
+
|
|
218
|
+
You need to install mongodb and openapi generator:
|
|
219
|
+
1. https://www.mongodb.com/docs/manual/installation/
|
|
220
|
+
2. https://openapi-generator.tech/docs/installation/
|
|
221
|
+
|
|
222
|
+
# Quick Start
|
|
223
|
+
This quick start create a example project developed by simpleapp-generator
|
|
224
|
+
1. Install `simpleapp-generator`
|
|
225
|
+
```sh
|
|
226
|
+
npm install -g simpleapp-generator
|
|
227
|
+
```
|
|
228
|
+
2. mkdir project folder for store frontend and backend codes
|
|
229
|
+
```sh
|
|
230
|
+
mkdir ~/myapp
|
|
231
|
+
cd myapp
|
|
232
|
+
```
|
|
233
|
+
3. generate sample project
|
|
234
|
+
```sh
|
|
235
|
+
simpleapp-generator -e person # -e mean use example schema "person". Currently only 1 example
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
4. run backend apiserver
|
|
239
|
+
```sh
|
|
240
|
+
cd backend
|
|
241
|
+
pnpm start:dev
|
|
242
|
+
```
|
|
243
|
+
5. browse to `http://localhost:8000/api` for swagger ui, `http://localhost:8000/api-yaml` for openapi documents
|
|
244
|
+
6. You may use vscode to see the example code in `backend/src/docs/pes`:
|
|
245
|
+
- pes.controller.ts //document api controller
|
|
246
|
+
- pes.service.ts //document service controller
|
|
247
|
+
- pes.type.ts, pes.apischema.ts, pes.model.ts //multiple datatype or schema
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
mkdir definations #we put json schema here
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
3. create configuration file `config.json`
|
|
261
|
+
```sh
|
|
262
|
+
echo '{"definationsFolder":"./definations","backendFolder":"./backend", "frontendFolder":"./frontend","openapi3Yaml":""}' > config.json
|
|
263
|
+
```
|
|
264
|
+
4. create below content and save as `~/myapp/definations/person.pes.jsonschema.json`
|
|
265
|
+
```json
|
|
266
|
+
{
|
|
267
|
+
"type": "object",
|
|
268
|
+
"properties": {
|
|
269
|
+
"name": {
|
|
270
|
+
"type": "object",
|
|
271
|
+
"properties": {
|
|
272
|
+
"firstName": {
|
|
273
|
+
"type": "string",
|
|
274
|
+
"examples": [
|
|
275
|
+
"John"
|
|
276
|
+
]
|
|
277
|
+
},
|
|
278
|
+
"lastName": {
|
|
279
|
+
"type": "string",
|
|
280
|
+
"examples": [
|
|
281
|
+
"Fox"
|
|
282
|
+
]
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
"age": {
|
|
287
|
+
"type": "integer",
|
|
288
|
+
"examples": [
|
|
289
|
+
20
|
|
290
|
+
]
|
|
291
|
+
},
|
|
292
|
+
"email": {
|
|
293
|
+
"type": "string",
|
|
294
|
+
"examples": [
|
|
295
|
+
"john@example.com"
|
|
296
|
+
],
|
|
297
|
+
"format": "email"
|
|
298
|
+
},
|
|
299
|
+
"dob": {
|
|
300
|
+
"type": "string",
|
|
301
|
+
"examples": [
|
|
302
|
+
"2000-01-01"
|
|
303
|
+
],
|
|
304
|
+
"format": "date"
|
|
305
|
+
},
|
|
306
|
+
"hobbies": {
|
|
307
|
+
"type": "array",
|
|
308
|
+
"items": {
|
|
309
|
+
"type": "string",
|
|
310
|
+
"examples": [
|
|
311
|
+
"badminton",
|
|
312
|
+
"dota",
|
|
313
|
+
"reading"
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
"addresses": {
|
|
318
|
+
"type": "array",
|
|
319
|
+
"items": {
|
|
320
|
+
"type": "object",
|
|
321
|
+
"required": [
|
|
322
|
+
"street1",
|
|
323
|
+
"street2",
|
|
324
|
+
"postcode"
|
|
325
|
+
],
|
|
326
|
+
"properties": {
|
|
327
|
+
"street1": {
|
|
328
|
+
"type": "string",
|
|
329
|
+
"examples": [
|
|
330
|
+
"11, Fox Road"
|
|
331
|
+
]
|
|
332
|
+
},
|
|
333
|
+
"street2": {
|
|
334
|
+
"type": "string",
|
|
335
|
+
"examples": [
|
|
336
|
+
"My Home Town"
|
|
337
|
+
]
|
|
338
|
+
},
|
|
339
|
+
"postcode": {
|
|
340
|
+
"type": "integer",
|
|
341
|
+
"examples": [
|
|
342
|
+
12345
|
|
343
|
+
]
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
5. generate backend and frontend codes, and define backend/.env `mongodb connection` string:
|
|
352
|
+
```sh
|
|
353
|
+
simpleapp-generator -c ./config.json
|
|
354
|
+
code backend # use vscode open backend project, edit .env
|
|
355
|
+
```
|
|
356
|
+
6. You can start backend server and try the generated api at `http://localhost:8000/api`
|
|
357
|
+
```sh
|
|
358
|
+
cd ~/myapp/backend
|
|
359
|
+
pnpm start:dev
|
|
360
|
+
```
|
|
361
|
+
7. Next we need more frontend work, put content of `http://localhost:8000/api-yaml` into `~/myapp/openapi.yaml`, and edit config.json as:
|
|
362
|
+
```json
|
|
363
|
+
{
|
|
364
|
+
"definationsFolder":"./definations",
|
|
365
|
+
"backendFolder":"./backend",
|
|
366
|
+
"frontendFolder":"./frontend",
|
|
367
|
+
"openapi3Yaml":"./openapi.yaml"
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
8. regenerate source code, and use vscode open both backend and frontend project:
|
|
371
|
+
```sh
|
|
372
|
+
simpleapp-generator -c ./config.json
|
|
373
|
+
code ./frontend ;
|
|
374
|
+
code ./backend ;
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
# The complete development process:
|
|
379
|
+
1. Prepare documents
|
|
380
|
+
a. Prepare sample json data
|
|
381
|
+
b. Convert `json` data to `jsonschema`
|
|
382
|
+
c. touch up jsonschema, like define require fields, format, minLength and etc
|
|
383
|
+
d. place json schema into `definations` folder
|
|
384
|
+
2. Generate source codes
|
|
385
|
+
a. generate source code into backend project
|
|
386
|
+
b. start backend service, obtain yaml content and save into project folder
|
|
387
|
+
c. re-generate source code, it create required codes for frontend
|
|
388
|
+
3. Begin Frontend development:
|
|
389
|
+
a. use vscode open frontend project
|
|
390
|
+
b. create user interface with several input fields, bind to generated simpleapp object
|
|
391
|
+
|
|
392
|
+
## 1. Prepare documents
|
|
393
|
+
1. [click here](https://www.convertsimple.com/convert-javascript-to-json/) allow you create json data with lesser effort. Lets use this example:
|
|
394
|
+
```json
|
|
395
|
+
{
|
|
396
|
+
"docNo": "SI001",
|
|
397
|
+
"customer": "My Customer Pte Ltd",
|
|
398
|
+
"amount": 200,
|
|
399
|
+
"products": [
|
|
400
|
+
"apple",
|
|
401
|
+
"orange"
|
|
402
|
+
],
|
|
403
|
+
"details": [
|
|
404
|
+
{
|
|
405
|
+
"item": "apple",
|
|
406
|
+
"qty": 100,
|
|
407
|
+
"unitprice": 1,
|
|
408
|
+
"subtotal": 100
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"item": "orange",
|
|
412
|
+
"qty": 100,
|
|
413
|
+
"unitprice": 1,
|
|
414
|
+
"subtotal": 100
|
|
415
|
+
}
|
|
416
|
+
],
|
|
417
|
+
"remarks": "need fast delivery"
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
b. Copy generated json data to [here](https://redocly.com/tools/json-to-json-schema) using below setting, you may define data type/format/required parameters according [jsonschema standard](https://json-schema.org/understanding-json-schema/reference/index.html)
|
|
421
|
+
```
|
|
422
|
+
output format: json
|
|
423
|
+
add example to schema: true
|
|
424
|
+
infer require property for array items: true
|
|
425
|
+
disable additionalProperty: true
|
|
426
|
+
```
|
|
427
|
+
Here is the result:
|
|
428
|
+
```json
|
|
429
|
+
{
|
|
430
|
+
"type": "object",
|
|
431
|
+
"properties": {
|
|
432
|
+
"docNo": {
|
|
433
|
+
"type": "string",
|
|
434
|
+
"examples": [
|
|
435
|
+
"SI001"
|
|
436
|
+
]
|
|
437
|
+
},
|
|
438
|
+
"customer": {
|
|
439
|
+
"type": "string",
|
|
440
|
+
"examples": [
|
|
441
|
+
"My Customer Pte Ltd"
|
|
442
|
+
]
|
|
443
|
+
},
|
|
444
|
+
"amount": {
|
|
445
|
+
"type": "integer",
|
|
446
|
+
"examples": [
|
|
447
|
+
200
|
|
448
|
+
]
|
|
449
|
+
},
|
|
450
|
+
"products": {
|
|
451
|
+
"type": "array",
|
|
452
|
+
"items": {
|
|
453
|
+
"type": "string",
|
|
454
|
+
"examples": [
|
|
455
|
+
"apple",
|
|
456
|
+
"orange"
|
|
457
|
+
]
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
"details": {
|
|
461
|
+
"type": "array",
|
|
462
|
+
"items": {
|
|
463
|
+
"type": "object",
|
|
464
|
+
"required": [
|
|
465
|
+
"item",
|
|
466
|
+
"qty",
|
|
467
|
+
"unitprice",
|
|
468
|
+
"subtotal"
|
|
469
|
+
],
|
|
470
|
+
"properties": {
|
|
471
|
+
"item": {
|
|
472
|
+
"type": "string",
|
|
473
|
+
"examples": [
|
|
474
|
+
"apple",
|
|
475
|
+
"orange"
|
|
476
|
+
]
|
|
477
|
+
},
|
|
478
|
+
"qty": {
|
|
479
|
+
"type": "integer",
|
|
480
|
+
"examples": [
|
|
481
|
+
100,
|
|
482
|
+
100
|
|
483
|
+
]
|
|
484
|
+
},
|
|
485
|
+
"unitprice": {
|
|
486
|
+
"type": "integer",
|
|
487
|
+
"examples": [
|
|
488
|
+
1,
|
|
489
|
+
1
|
|
490
|
+
]
|
|
491
|
+
},
|
|
492
|
+
"subtotal": {
|
|
493
|
+
"type": "integer",
|
|
494
|
+
"examples": [
|
|
495
|
+
100,
|
|
496
|
+
100
|
|
497
|
+
]
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
},
|
|
502
|
+
"remarks": {
|
|
503
|
+
"type": "string",
|
|
504
|
+
"examples": [
|
|
505
|
+
"need fast delivery"
|
|
506
|
+
]
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
```
|
|
511
|
+
c. save the json data into `definations` folder
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
## Backend NestJS project preparation
|
|
518
|
+
1. install backend nest application: `npm i -g pnpm @nestjs/cli` (cli tools for pnpm and nestjs)
|
|
519
|
+
2. create a folder `~/myapp`
|
|
520
|
+
3. cd `~/myapp`
|
|
521
|
+
4. create blank nest project `nest new backend`, pick `pnpm`
|
|
522
|
+
5. enter backend folder: `cd backend`
|
|
523
|
+
6. install dependency: `pnpm install --save @nestjs/swagger @nestjs/mongoose mongoose ajv ajv-formats @nestjs/config` (ignore ✕ missing peer webpack)
|
|
524
|
+
7. create .env file with following settings:
|
|
525
|
+
```sh
|
|
526
|
+
MONGODB_URL='mongodb://<user>:<pass>@<host>:<port>/<db>?authMechanism=DEFAULT'
|
|
527
|
+
HTTP_PORT=8000
|
|
528
|
+
PROJECT_NAME='SimpleApp Demo1'
|
|
529
|
+
PROJECT_DESCRIPTION='Try CRUD'
|
|
530
|
+
PROJECT_Version='1.0.0'
|
|
531
|
+
```
|
|
532
|
+
7. change `src/main.ts`, allow openapi document:
|
|
533
|
+
```ts
|
|
534
|
+
import { NestFactory } from '@nestjs/core';
|
|
535
|
+
import { AppModule } from './app.module';
|
|
536
|
+
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
|
537
|
+
|
|
538
|
+
async function bootstrap() {
|
|
539
|
+
const app = await NestFactory.create(AppModule);
|
|
540
|
+
app.enableCors();
|
|
541
|
+
const config = new DocumentBuilder()
|
|
542
|
+
.setTitle(process.env.PROJECT_NAME)
|
|
543
|
+
.setDescription(process.env.PROJECT_DESCRIPTION)
|
|
544
|
+
.setVersion(process.env.PROJECT_VERSION)
|
|
545
|
+
.build();
|
|
546
|
+
const document = SwaggerModule.createDocument(app, config);
|
|
547
|
+
SwaggerModule.setup('api', app, document, {
|
|
548
|
+
swaggerOptions: { showExtensions: true },
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
await app.listen(process.env.HTTP_PORT); //listen which port
|
|
552
|
+
}
|
|
553
|
+
bootstrap();
|
|
554
|
+
```
|
|
555
|
+
9. start backend server `pnpm start:dev`, monitor [http://localhost:3000/api](http://localhost:3000/api)
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
## Frontend NuxtJS project preparation (or, any others framework if you have know how)
|
|
559
|
+
1. `cd ~/myapp`
|
|
560
|
+
2. create new frontend nuxt project `npx nuxi@latest init frontend`
|
|
561
|
+
3. `cd frontend`
|
|
562
|
+
4. install required package: `pnpm install ajv ajv-formats axios json-schema`
|
|
563
|
+
5. create .env file with below content
|
|
564
|
+
```sh
|
|
565
|
+
SIMPLEAPP_BACKEND_URL=http://localhost:8000
|
|
566
|
+
PORT=8800
|
|
567
|
+
```
|
|
568
|
+
6. run frontend: `pnpm dev -o`
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
## setup Mongodb
|
|
572
|
+
1. you can use mongodb, either docker or install binary
|
|
573
|
+
https://www.mongodb.com/docs/manual/installation/
|
|
574
|
+
** remember create database, and define suitable credentials (user/password)
|
|
575
|
+
|
|
576
|
+
## Setup openapi-generator
|
|
577
|
+
Refer below:
|
|
578
|
+
https://openapi-generator.tech/docs/installation/
|
|
579
|
+
|
|
580
|
+
I'm using mac, so i use `brew install openapi-generator`
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
# Job Begin!
|
|
584
|
+
3 steps:
|
|
585
|
+
1. Prepare json schema
|
|
586
|
+
2. use json schema generate frontend and backend codes
|
|
587
|
+
3. persom simple development
|
|
588
|
+
|
|
589
|
+
## 1. Prepare sample data schema
|
|
590
|
+
1. lets assume we have a sample data:
|
|
591
|
+
```json
|
|
592
|
+
{
|
|
593
|
+
"name":{"firstName":"John","lastName":"Fox"},
|
|
594
|
+
"age":20,
|
|
595
|
+
"email":"john@example.com",
|
|
596
|
+
"dob":"2000-01-01",
|
|
597
|
+
"hobbies":["badminton","dota","reading"],
|
|
598
|
+
"addresses": [{"street1":"11, Fox Road","street2":"My Home Town","postcode":12345}]
|
|
599
|
+
}
|
|
600
|
+
```
|
|
601
|
+
2. Generate it become `jsonschema` [here](https://redocly.com/tools/json-to-json-schema), format as json. Follow below settings:
|
|
602
|
+
```
|
|
603
|
+
add example to schema: true
|
|
604
|
+
infer require property for array items: true
|
|
605
|
+
disable additionalProperty: true
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
Below is the sample of jsonschema:
|
|
609
|
+
```json
|
|
610
|
+
{
|
|
611
|
+
"type": "object",
|
|
612
|
+
"properties": {
|
|
613
|
+
"name": {
|
|
614
|
+
"type": "object",
|
|
615
|
+
"properties": {
|
|
616
|
+
"firstName": {
|
|
617
|
+
"type": "string",
|
|
618
|
+
"examples": [
|
|
619
|
+
"John"
|
|
620
|
+
]
|
|
621
|
+
},
|
|
622
|
+
"lastName": {
|
|
623
|
+
"type": "string",
|
|
624
|
+
"examples": [
|
|
625
|
+
"Fox"
|
|
626
|
+
]
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
"age": {
|
|
631
|
+
"type": "integer",
|
|
632
|
+
"examples": [
|
|
633
|
+
20
|
|
634
|
+
]
|
|
635
|
+
},
|
|
636
|
+
"email": {
|
|
637
|
+
"type": "string",
|
|
638
|
+
"examples": [
|
|
639
|
+
"john@example.com"
|
|
640
|
+
],
|
|
641
|
+
"format": "email"
|
|
642
|
+
},
|
|
643
|
+
"dob": {
|
|
644
|
+
"type": "string",
|
|
645
|
+
"examples": [
|
|
646
|
+
"2000-01-01"
|
|
647
|
+
],
|
|
648
|
+
"format": "date"
|
|
649
|
+
},
|
|
650
|
+
"hobbies": {
|
|
651
|
+
"type": "array",
|
|
652
|
+
"items": {
|
|
653
|
+
"type": "string",
|
|
654
|
+
"examples": [
|
|
655
|
+
"badminton",
|
|
656
|
+
"dota",
|
|
657
|
+
"reading"
|
|
658
|
+
]
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
"addresses": {
|
|
662
|
+
"type": "array",
|
|
663
|
+
"items": {
|
|
664
|
+
"type": "object",
|
|
665
|
+
"required": [
|
|
666
|
+
"street1",
|
|
667
|
+
"street2",
|
|
668
|
+
"postcode"
|
|
669
|
+
],
|
|
670
|
+
"properties": {
|
|
671
|
+
"street1": {
|
|
672
|
+
"type": "string",
|
|
673
|
+
"examples": [
|
|
674
|
+
"11, Fox Road"
|
|
675
|
+
]
|
|
676
|
+
},
|
|
677
|
+
"street2": {
|
|
678
|
+
"type": "string",
|
|
679
|
+
"examples": [
|
|
680
|
+
"My Home Town"
|
|
681
|
+
]
|
|
682
|
+
},
|
|
683
|
+
"postcode": {
|
|
684
|
+
"type": "integer",
|
|
685
|
+
"examples": [
|
|
686
|
+
12345
|
|
687
|
+
]
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
## Generate Code
|
|
697
|
+
1. install simpleapp-generetor `npm install -g simpleapp-generator`
|
|
698
|
+
2. create a folder `~/myapp/definations`
|
|
699
|
+
3. copy above jsonschema example as `~/myapp/definations/person.ps.jsonschema.json`.
|
|
700
|
+
* `person`: unique document name (small letter alphabet `[a-z]`)
|
|
701
|
+
* `ps`: unique document type (small letter `[a-z]`)
|
|
702
|
+
* `jsonschema.json`: all files ending with this extension will process
|
|
703
|
+
4. create `~/myapp/config.json` with below content
|
|
704
|
+
```json
|
|
705
|
+
{
|
|
706
|
+
"definationsFolder":"./definations",
|
|
707
|
+
"backendFolder":"./mybackend",
|
|
708
|
+
"backendPort":"8000",
|
|
709
|
+
"mongoConnectStr":"mongodb://<user>:<pass>@<host>:<port>/<db>?authMechanism=DEFAULT",
|
|
710
|
+
"frontendFolder":"./myfrontend",
|
|
711
|
+
"frontendPort":"8080",
|
|
712
|
+
"openapi3Yaml":"./openapi.yaml",
|
|
713
|
+
}
|
|
714
|
+
```
|
|
715
|
+
5. run `simpleapp-generator -c ./config.json`
|
|
716
|
+
6. restart nestjs, the microservice is ready and you can test at `http://localhost:8000/api`. All generated api accessible via swagger-ui.
|
|
717
|
+
7. Frontend need further work. Browse `http://localhost:8000/api-yaml`, save content as `openapi.yaml`
|
|
718
|
+
8. Rerun `simpleapp-generator -c ./config.json`, it will help us to generate axios executable using openapi.yaml
|
|
719
|
+
9. use vscode open both `~/myapp/frontend` and `~/myapp/backend`
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
## perform simple development
|
|
724
|
+
1. in `frontend` project, edit `app.vue`, put in below code:
|
|
725
|
+
```vue
|
|
726
|
+
<template>
|
|
727
|
+
<div>
|
|
728
|
+
<div>
|
|
729
|
+
<label>Firstname</label>
|
|
730
|
+
<input v-model="reactivedata.name.firstName">
|
|
731
|
+
</div>
|
|
732
|
+
{{ reactivedata }}
|
|
733
|
+
<button @click="person.create().then((res)=>console.log(res.data))">try</button>
|
|
734
|
+
</div>
|
|
735
|
+
</template>
|
|
736
|
+
<script setup lang="ts">
|
|
737
|
+
import {PersonDoc} from './server/docs/PersonDoc'
|
|
738
|
+
const person = new PersonDoc()
|
|
739
|
+
|
|
740
|
+
// person.update().then((res)=>console.log("dosomething"))
|
|
741
|
+
// person.delete('record-id').then((res)=>console.log("dosomething"))
|
|
742
|
+
// person.getById('record-id').then((res)=>console.log("dosomething"))
|
|
743
|
+
// person.list().then((res)=>console.log(res))
|
|
744
|
+
const noreactivedata = person.getData() //give not reactive data, it cant apply 2 way data binding
|
|
745
|
+
const reactivedata = person.getReactiveData() //give vue reactive data, it can apply 2 way data binding using v-model
|
|
746
|
+
</script>
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
We notice:
|
|
750
|
+
1. `PersonDoc` auto generated, it come with plenty of build in crud features which you can use without knowing API:
|
|
751
|
+
```typescript
|
|
752
|
+
person.create().then((res)=>console.log("dosomething"))
|
|
753
|
+
person.update().then((res)=>console.log("dosomething"))
|
|
754
|
+
person.delete('record-id').then((res)=>console.log("dosomething"))
|
|
755
|
+
person.getById('record-id').then((res)=>console.log("dosomething"))
|
|
756
|
+
person.list().then((res)=>console.log(res))
|
|
757
|
+
```
|
|
758
|
+
2. `person.getData()` gave reactive object, we can bind all properties directly to `vue` component using `v-model`
|
|
759
|
+
3. you may try add more input bind to `reactivedata.name.lastName`,`reactivedata.email`, `reactivedata.age` and monitor result
|
|
760
|
+
4. `button` can directly trigger `save` method from person.getData()
|
|
761
|
+
5. You wont able to save the record because it not pass validation rules, check browser console it tell you what is happening
|
|
762
|
+
6. There is UI component `simpleapp-uicomponent` which can integrate nicely with with `PersonDoc`. Refer the link [here](...)
|
|
763
|
+
|
|
764
|
+
# We can do more With SimpleApp
|
|
765
|
+
## no time for full documentation yet
|
|
766
|
+
1. Monitor variable change at frontend
|
|
767
|
+
step 1: add new methods for frontend's class `PesonDoc.ts`
|
|
768
|
+
```
|
|
769
|
+
watchChanges = ()=>{
|
|
770
|
+
watch(this.getReactiveData(),(newdata)=>{
|
|
771
|
+
this.getReactiveData().age=calculateAge(newdata.dob)
|
|
772
|
+
//apply others changes here
|
|
773
|
+
})
|
|
774
|
+
}
|
|
775
|
+
```
|
|
776
|
+
step 2: edit `app.vue` to on the watcher
|
|
777
|
+
```typescript
|
|
778
|
+
//others codes
|
|
779
|
+
const person = new PersonDoc()
|
|
780
|
+
person.watchChanges() //<-- add this line to on watcher at frontend
|
|
781
|
+
//others codes
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
2. create more api to `person`, such as `post /person/:id/sendEmail {title:"title",body:"body"}`
|
|
785
|
+
step 1: edit backend `<backend>/src/docs/pes/pes.controller.ts`, add new source code between `<begin-controller-code>` and `<end-controller-code>`:
|
|
786
|
+
```typescript
|
|
787
|
+
//<begin-controller-code>
|
|
788
|
+
//new api, wont override when regenerate code
|
|
789
|
+
@Get('/try/:id')
|
|
790
|
+
@ApiResponse({
|
|
791
|
+
status: 200,
|
|
792
|
+
description: 'success',
|
|
793
|
+
type: pesapischema.Person,
|
|
794
|
+
})
|
|
795
|
+
@ApiResponse({ status: 404, description: 'Document not found' })
|
|
796
|
+
@ApiResponse({ status: 500, description: 'Internal error' })
|
|
797
|
+
@ApiOperation({ operationId: 'newFindOne' }) //important, frontend access it via person.newFindOne()
|
|
798
|
+
async newFindOne(@Param('id') id: string) {
|
|
799
|
+
return this._findOne(id);
|
|
800
|
+
}
|
|
801
|
+
//<end-controller-code>
|
|
802
|
+
```
|
|
803
|
+
step 2: try browse to `http://localhost:8000/api` to check new api appear or not.
|
|
804
|
+
step 3: You shall regenerate the code
|
|
805
|
+
```bash
|
|
806
|
+
simpleapp-generator -c ./config.json
|
|
807
|
+
```
|
|
808
|
+
step 4: go frontend project, edit `app.vue` you may try type `person.newFindOne()` see new method exists?
|
|
809
|
+
|
|
810
|
+
step 3: Regenerate code for frontend
|
|
811
|
+
|
|
812
|
+
4. create backend only execution for `person`. It is useful cause some work only
|
|
813
|
+
step 1: Edit backend `backend/src/docs/pes/pes.service.ts`, add new source code between `<begin-backend-code>` and `<end-backend-code>`:
|
|
814
|
+
```typescript
|
|
815
|
+
//<begin-backend-code>
|
|
816
|
+
//new method, wont override when regenerate code
|
|
817
|
+
logSomething = () => {
|
|
818
|
+
console.log('Access try api');
|
|
819
|
+
};
|
|
820
|
+
//<end-backend-code>
|
|
821
|
+
```
|
|
822
|
+
step 2: modify `<backend>/src/docs/pes/pes.controller.ts`, call the new method
|
|
823
|
+
```typescript
|
|
824
|
+
async newFindOne(@Param('id') id: string) {
|
|
825
|
+
this.service.logSomething(); //this.service is our service class
|
|
826
|
+
return this._findOne(id);
|
|
827
|
+
}
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
5. create frontend only code for `person`, such as:
|
|
832
|
+
`person.addHobbies('hobby1')`,`person.addAddress({})`,`person.delAddress(index:number)` edit `newFindOne`:
|
|
833
|
+
```
|
|
834
|
+
```
|
|
835
|
+
6. create bothend code for `person`
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
|
|
839
|
+
foreign key
|
|
840
|
+
cat
|
|
841
|
+
category_id
|
|
842
|
+
category_code
|
|
843
|
+
category_name
|
|
844
|
+
|
|
845
|
+
product
|
|
846
|
+
product_id
|
|
847
|
+
product_code
|
|
848
|
+
product_name
|
|
849
|
+
category => category_id: category_code
|
|
850
|
+
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
invoice
|
|
854
|
+
invoice_id
|
|
855
|
+
invoice_no
|
|
856
|
+
invoice_date
|
|
857
|
+
total
|
|
858
|
+
details =>
|
|
859
|
+
product => product_id: product_code
|
|
860
|
+
qty
|
|
861
|
+
price
|
|
862
|
+
subtotal
|
|
863
|
+
|
|
864
|
+
order
|
|
865
|
+
order_id
|
|
866
|
+
order_no
|
|
867
|
+
order_date
|
|
868
|
+
total
|
|
869
|
+
details =>
|
|
870
|
+
product => product_id: product_code
|
|
871
|
+
qty
|
|
872
|
+
price
|
|
873
|
+
subtotal
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
cat => foreignkey: []
|
|
877
|
+
prd => foreignkey: category => category
|
|
878
|
+
invoice => foreignkey: detail.product=>product
|
|
879
|
+
order => foreignkey: detail.product=>product
|
|
880
|
+
|
|
881
|
+
cat =[product.category]
|
|
882
|
+
product=[invoice.detail.product, order.detail.product]
|