@steedos/service-rest 2.5.3-beta.19
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 +6 -0
- package/consts.js +10 -0
- package/package.json +21 -0
- package/package.service.js +417 -0
package/consts.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@steedos/service-rest",
|
|
3
|
+
"version": "2.5.3-beta.19",
|
|
4
|
+
"main": "package.service.js",
|
|
5
|
+
"private": false,
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"steedos"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {},
|
|
13
|
+
"description": "steedos package",
|
|
14
|
+
"repository": {},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@steedos/objectql": "2.5.3-beta.19",
|
|
18
|
+
"@steedos/service-object-mixin": "2.5.3-beta.19",
|
|
19
|
+
"lodash": "^4.17.21"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @Author: sunhaolin@hotoa.com
|
|
3
|
+
* @Date: 2023-03-23 15:12:14
|
|
4
|
+
* @LastEditors: sunhaolin@hotoa.com
|
|
5
|
+
* @LastEditTime: 2023-06-15 13:50:16
|
|
6
|
+
* @Description:
|
|
7
|
+
*/
|
|
8
|
+
"use strict";
|
|
9
|
+
// @ts-check
|
|
10
|
+
const serviceObjectMixin = require('@steedos/service-object-mixin');
|
|
11
|
+
const { QUERY_DOCS_TOP } = require('./consts')
|
|
12
|
+
const _ = require('lodash')
|
|
13
|
+
const { getObject } = require('@steedos/objectql');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {import('moleculer').Context} Context Moleculer's Context
|
|
17
|
+
*/
|
|
18
|
+
module.exports = {
|
|
19
|
+
name: 'rest',
|
|
20
|
+
namespace: "steedos",
|
|
21
|
+
mixins: [serviceObjectMixin],
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Settings
|
|
25
|
+
*/
|
|
26
|
+
settings: {
|
|
27
|
+
// Base path
|
|
28
|
+
rest: "/rest",
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Dependencies
|
|
33
|
+
*/
|
|
34
|
+
dependencies: [],
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Actions
|
|
38
|
+
*/
|
|
39
|
+
actions: {
|
|
40
|
+
health: {
|
|
41
|
+
rest: {
|
|
42
|
+
method: "GET",
|
|
43
|
+
path: "/health"
|
|
44
|
+
},
|
|
45
|
+
async handler(ctx) {
|
|
46
|
+
return 'ok'
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
/**
|
|
50
|
+
* @api {POST} /api/v1/rest/:objectName/listRecords 获取列表
|
|
51
|
+
* @apiVersion 0.0.0
|
|
52
|
+
* @apiName find
|
|
53
|
+
* @apiGroup @steedos/service-rest
|
|
54
|
+
* @apiParam {String} objectName 对象API Name,如:contracts
|
|
55
|
+
* @apiBody {String[]} [fields] 字段名,如:["name", "description"]
|
|
56
|
+
* @apiBody {Object[]} [filters] 过滤条件,如:[['name', '=', 'test'],['amount', '>', 100]]
|
|
57
|
+
* @apiBody {Number} [top] 获取条数,如:10,最多5000
|
|
58
|
+
* @apiBody {Number} [skip] 跳过条数,如:10
|
|
59
|
+
* @apiBody {String} [sort] 排序,如:'name desc'
|
|
60
|
+
* @apiSuccess {Object[]} listRecords 记录列表
|
|
61
|
+
* @apiSuccessExample {json} Success-Response:
|
|
62
|
+
* HTTP/1.1 200 OK
|
|
63
|
+
* {
|
|
64
|
+
* records: [{
|
|
65
|
+
* "_id": "5e7d1b9b9c9d4400001d1b9b",
|
|
66
|
+
* "name": "test",
|
|
67
|
+
* ...
|
|
68
|
+
* }]
|
|
69
|
+
* }
|
|
70
|
+
* @apiErrorExample {json} Error-Response:
|
|
71
|
+
* HTTP/1.1 404 Error
|
|
72
|
+
* {
|
|
73
|
+
* "error": "Service 'rest.contracts' is not found.",
|
|
74
|
+
* "detail": {
|
|
75
|
+
* "code": "404",
|
|
76
|
+
* "type": "SERVICE_NOT_FOUND",
|
|
77
|
+
* "data": {
|
|
78
|
+
* "action": "rest.contracts"
|
|
79
|
+
* }
|
|
80
|
+
* }
|
|
81
|
+
* }
|
|
82
|
+
*/
|
|
83
|
+
find: {
|
|
84
|
+
rest: {
|
|
85
|
+
method: "POST",
|
|
86
|
+
path: "/:objectName/listRecords"
|
|
87
|
+
},
|
|
88
|
+
params: {
|
|
89
|
+
objectName: { type: "string" },
|
|
90
|
+
fields: { type: 'array', items: "string", optional: true },
|
|
91
|
+
filters: [{ type: 'array', optional: true }, { type: 'string', optional: true }],
|
|
92
|
+
top: { type: 'number', optional: true },
|
|
93
|
+
skip: { type: 'number', optional: true },
|
|
94
|
+
sort: { type: 'string', optional: true }
|
|
95
|
+
},
|
|
96
|
+
async handler(ctx) {
|
|
97
|
+
const params = ctx.params
|
|
98
|
+
const { objectName } = params
|
|
99
|
+
const userSession = ctx.meta.user;
|
|
100
|
+
|
|
101
|
+
if (_.has(params, "top")) { // 如果top小于1,不返回数据
|
|
102
|
+
if (params.top < 1) {
|
|
103
|
+
return []
|
|
104
|
+
}
|
|
105
|
+
if (params.top > QUERY_DOCS_TOP) {
|
|
106
|
+
params.top = QUERY_DOCS_TOP // 最多返回5000条数据
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const query = {}
|
|
111
|
+
if (_.has(params, "filters")) {
|
|
112
|
+
query.filters = params.filters
|
|
113
|
+
}
|
|
114
|
+
if (_.has(params, "fields")) {
|
|
115
|
+
query.fields = params.fields
|
|
116
|
+
}
|
|
117
|
+
if (_.has(params, "top")) {
|
|
118
|
+
query.top = params.top
|
|
119
|
+
}
|
|
120
|
+
if (_.has(params, "skip")) {
|
|
121
|
+
query.skip = params.skip
|
|
122
|
+
}
|
|
123
|
+
if (_.has(params, "sort")) {
|
|
124
|
+
query.sort = params.sort
|
|
125
|
+
}
|
|
126
|
+
const records = await this.find(objectName, query, userSession)
|
|
127
|
+
return {
|
|
128
|
+
records
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
/**
|
|
133
|
+
* @api {GET} /api/v1/rest/:objectName/:id 获取单条记录
|
|
134
|
+
* @apiVersion 0.0.0
|
|
135
|
+
* @apiName findOne
|
|
136
|
+
* @apiGroup @steedos/service-rest
|
|
137
|
+
* @apiParam {String} objectName 对象API Name,如:contracts
|
|
138
|
+
* @apiParam {String} id 记录id,如:5e7d1b9b9c9d4400001d1b9b
|
|
139
|
+
* @apiQuery {String} [fields] 字段名,如:'["name","description"]'
|
|
140
|
+
* @apiSuccess {Object} record 记录信息
|
|
141
|
+
* @apiSuccessExample {json} Success-Response:
|
|
142
|
+
* HTTP/1.1 200 OK
|
|
143
|
+
* {
|
|
144
|
+
* "_id": "5e7d1b9b9c9d4400001d1b9b",
|
|
145
|
+
* "name": "test",
|
|
146
|
+
* ...
|
|
147
|
+
* }
|
|
148
|
+
* @apiErrorExample {json} Error-Response:
|
|
149
|
+
* HTTP/1.1 404 Error
|
|
150
|
+
* {
|
|
151
|
+
* "error": "Service 'rest.contracts' is not found.",
|
|
152
|
+
* "detail": {
|
|
153
|
+
* "code": "404",
|
|
154
|
+
* "type": "SERVICE_NOT_FOUND",
|
|
155
|
+
* "data": {
|
|
156
|
+
* "action": "rest.contracts"
|
|
157
|
+
* }
|
|
158
|
+
* }
|
|
159
|
+
* }
|
|
160
|
+
*/
|
|
161
|
+
findOne: {
|
|
162
|
+
rest: {
|
|
163
|
+
method: "GET",
|
|
164
|
+
path: "/:objectName/:id"
|
|
165
|
+
},
|
|
166
|
+
params: {
|
|
167
|
+
objectName: { type: "string" },
|
|
168
|
+
id: { type: "any" },
|
|
169
|
+
fields: { type: 'string', optional: true },
|
|
170
|
+
},
|
|
171
|
+
async handler(ctx) {
|
|
172
|
+
const { objectName, id, fields } = ctx.params
|
|
173
|
+
const userSession = ctx.meta.user;
|
|
174
|
+
const query = {}
|
|
175
|
+
if (fields) {
|
|
176
|
+
query.fields = JSON.parse(fields)
|
|
177
|
+
}
|
|
178
|
+
return this.findOne(objectName, id, query, userSession)
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
/**
|
|
182
|
+
* @api {POST} /api/v1/rest/:objectName 新增记录
|
|
183
|
+
* @apiVersion 0.0.0
|
|
184
|
+
* @apiName insert
|
|
185
|
+
* @apiGroup @steedos/service-rest
|
|
186
|
+
* @apiParam {String} objectName 对象API Name,如:contracts
|
|
187
|
+
* @apiBody {Object} doc 新增的内容,如:{ name: 'test', description: 'test' }
|
|
188
|
+
* @apiSuccess {Object} record 新记录信息
|
|
189
|
+
* @apiSuccessExample {json} Success-Response:
|
|
190
|
+
* HTTP/1.1 200 OK
|
|
191
|
+
* {
|
|
192
|
+
* "_id": "5e7d1b9b9c9d4400001d1b9b",
|
|
193
|
+
* "name": "test",
|
|
194
|
+
* ...
|
|
195
|
+
* }
|
|
196
|
+
* @apiErrorExample {json} Error-Response:
|
|
197
|
+
* HTTP/1.1 404 Error
|
|
198
|
+
* {
|
|
199
|
+
* "error": "Service 'rest.contracts' is not found.",
|
|
200
|
+
* "detail": {
|
|
201
|
+
* "code": "404",
|
|
202
|
+
* "type": "SERVICE_NOT_FOUND",
|
|
203
|
+
* "data": {
|
|
204
|
+
* "action": "rest.contracts"
|
|
205
|
+
* }
|
|
206
|
+
* }
|
|
207
|
+
* }
|
|
208
|
+
*/
|
|
209
|
+
insert: {
|
|
210
|
+
rest: {
|
|
211
|
+
method: "POST",
|
|
212
|
+
path: "/:objectName"
|
|
213
|
+
},
|
|
214
|
+
params: {
|
|
215
|
+
objectName: { type: "string" },
|
|
216
|
+
doc: { type: "object" }
|
|
217
|
+
},
|
|
218
|
+
async handler(ctx) {
|
|
219
|
+
const userSession = ctx.meta.user;
|
|
220
|
+
const { objectName, doc } = ctx.params;
|
|
221
|
+
const object = getObject(objectName)
|
|
222
|
+
let data = '';
|
|
223
|
+
if (_.isString(doc)) {
|
|
224
|
+
data = JSON.parse(doc);
|
|
225
|
+
} else {
|
|
226
|
+
data = JSON.parse(JSON.stringify(doc));
|
|
227
|
+
}
|
|
228
|
+
if (userSession && (await object.getField('space'))) {
|
|
229
|
+
data.space = userSession.spaceId;
|
|
230
|
+
}
|
|
231
|
+
return this.insert(objectName, data, userSession)
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
/**
|
|
235
|
+
* @api {PUT} /api/v1/rest/:objectName/:id 更新记录
|
|
236
|
+
* @apiVersion 0.0.0
|
|
237
|
+
* @apiName update
|
|
238
|
+
* @apiGroup @steedos/service-rest
|
|
239
|
+
* @apiParam {String} objectName 对象API Name,如:contracts
|
|
240
|
+
* @apiParam {String} id 记录id,如:5e7d1b9b9c9d4400001d1b9b
|
|
241
|
+
* @apiBody {Object} doc 更新的内容,如:{ name: 'test', description: 'test' }
|
|
242
|
+
* @apiSuccess {Object} record 新记录信息
|
|
243
|
+
* @apiSuccessExample {json} Success-Response:
|
|
244
|
+
* HTTP/1.1 200 OK
|
|
245
|
+
* {
|
|
246
|
+
* "_id": "5e7d1b9b9c9d4400001d1b9b",
|
|
247
|
+
* "name": "test",
|
|
248
|
+
* ...
|
|
249
|
+
* }
|
|
250
|
+
* @apiErrorExample {json} Error-Response:
|
|
251
|
+
* HTTP/1.1 404 Error
|
|
252
|
+
* {
|
|
253
|
+
* "error": "Service 'rest.contracts' is not found.",
|
|
254
|
+
* "detail": {
|
|
255
|
+
* "code": "404",
|
|
256
|
+
* "type": "SERVICE_NOT_FOUND",
|
|
257
|
+
* "data": {
|
|
258
|
+
* "action": "rest.contracts"
|
|
259
|
+
* }
|
|
260
|
+
* }
|
|
261
|
+
* }
|
|
262
|
+
*/
|
|
263
|
+
update: {
|
|
264
|
+
rest: {
|
|
265
|
+
method: "PUT",
|
|
266
|
+
path: "/:objectName/:id"
|
|
267
|
+
},
|
|
268
|
+
params: {
|
|
269
|
+
objectName: { type: "string" },
|
|
270
|
+
id: { type: "any" },
|
|
271
|
+
doc: { type: "object" }
|
|
272
|
+
},
|
|
273
|
+
async handler(ctx) {
|
|
274
|
+
const userSession = ctx.meta.user;
|
|
275
|
+
const { objectName, id, doc } = ctx.params;
|
|
276
|
+
let data = '';
|
|
277
|
+
if (_.isString(doc)) {
|
|
278
|
+
data = JSON.parse(doc);
|
|
279
|
+
} else {
|
|
280
|
+
data = JSON.parse(JSON.stringify(doc));
|
|
281
|
+
}
|
|
282
|
+
delete data.space;
|
|
283
|
+
return this.update(objectName, id, data, userSession)
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
/**
|
|
287
|
+
* @api {DELETE} /api/v1/rest/:objectName/:id 删除记录
|
|
288
|
+
* @apiVersion 0.0.0
|
|
289
|
+
* @apiName delete
|
|
290
|
+
* @apiGroup @steedos/service-rest
|
|
291
|
+
* @apiParam {String} objectName 对象API Name,如:contracts
|
|
292
|
+
* @apiParam {String} id 记录id,如:5e7d1b9b9c9d4400001d1b9b
|
|
293
|
+
* @apiSuccess {Object} record 新记录信息
|
|
294
|
+
* @apiSuccessExample {json} Success-Response:
|
|
295
|
+
* HTTP/1.1 200 OK
|
|
296
|
+
* {
|
|
297
|
+
* "deleted": true,
|
|
298
|
+
* "id": "5e7d1b9b9c9d4400001d1b9b",
|
|
299
|
+
* }
|
|
300
|
+
* @apiErrorExample {json} Error-Response:
|
|
301
|
+
* HTTP/1.1 404 Error
|
|
302
|
+
* {
|
|
303
|
+
* "error": "Service 'rest.contracts' is not found.",
|
|
304
|
+
* "detail": {
|
|
305
|
+
* "code": "404",
|
|
306
|
+
* "type": "SERVICE_NOT_FOUND",
|
|
307
|
+
* "data": {
|
|
308
|
+
* "action": "rest.contracts"
|
|
309
|
+
* }
|
|
310
|
+
* }
|
|
311
|
+
* }
|
|
312
|
+
*/
|
|
313
|
+
delete: {
|
|
314
|
+
rest: {
|
|
315
|
+
method: "DELETE",
|
|
316
|
+
path: "/:objectName/:id"
|
|
317
|
+
},
|
|
318
|
+
params: {
|
|
319
|
+
objectName: { type: "string" },
|
|
320
|
+
id: { type: "any" }
|
|
321
|
+
},
|
|
322
|
+
async handler(ctx) {
|
|
323
|
+
const userSession = ctx.meta.user;
|
|
324
|
+
const { objectName, id } = ctx.params;
|
|
325
|
+
const objectConfig = await getObject(objectName).getConfig()
|
|
326
|
+
const enableTrash = objectConfig.enable_trash
|
|
327
|
+
if (!enableTrash) {
|
|
328
|
+
await this.delete(objectName, id, userSession)
|
|
329
|
+
} else {
|
|
330
|
+
const data = {
|
|
331
|
+
is_deleted: true,
|
|
332
|
+
deleted: new Date(),
|
|
333
|
+
deleted_by: userSession ? userSession.userId : null
|
|
334
|
+
}
|
|
335
|
+
await this.update(objectName, id, data, userSession)
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
"deleted": true,
|
|
339
|
+
"id": id
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Events
|
|
348
|
+
*/
|
|
349
|
+
events: {
|
|
350
|
+
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Methods
|
|
355
|
+
*/
|
|
356
|
+
methods: {
|
|
357
|
+
find: {
|
|
358
|
+
async handler(objectName, query, userSession) {
|
|
359
|
+
const obj = this.getObject(objectName)
|
|
360
|
+
if (objectName == 'users') {
|
|
361
|
+
return await obj.find(query)
|
|
362
|
+
}
|
|
363
|
+
return await obj.find(query, userSession)
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
findOne: {
|
|
367
|
+
async handler(objectName, id, query, userSession) {
|
|
368
|
+
const obj = this.getObject(objectName)
|
|
369
|
+
if (objectName == 'users') {
|
|
370
|
+
return await obj.findOne(id, query)
|
|
371
|
+
}
|
|
372
|
+
return await obj.findOne(id, query, userSession)
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
insert: {
|
|
376
|
+
async handler(objectName, doc, userSession) {
|
|
377
|
+
const obj = this.getObject(objectName)
|
|
378
|
+
return await obj.insert(doc, userSession)
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
update: {
|
|
382
|
+
async handler(objectName, id, doc, userSession) {
|
|
383
|
+
const obj = this.getObject(objectName)
|
|
384
|
+
return await obj.update(id, doc, userSession)
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
delete: {
|
|
388
|
+
async handler(objectName, id, userSession) {
|
|
389
|
+
const obj = this.getObject(objectName)
|
|
390
|
+
return await obj.delete(id, userSession)
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Service created lifecycle event handler
|
|
397
|
+
*/
|
|
398
|
+
created() {
|
|
399
|
+
},
|
|
400
|
+
|
|
401
|
+
merged(schema) {
|
|
402
|
+
},
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Service started lifecycle event handler
|
|
406
|
+
*/
|
|
407
|
+
async started() {
|
|
408
|
+
|
|
409
|
+
},
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Service stopped lifecycle event handler
|
|
413
|
+
*/
|
|
414
|
+
async stopped() {
|
|
415
|
+
|
|
416
|
+
}
|
|
417
|
+
};
|