@hitchy/plugin-odem-rest 0.6.0 → 0.7.0
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/api/services/odem-rest/cors.js +1 -1
- package/index.js +99 -90
- package/package.json +6 -7
- package/readme.md +8 -8
package/index.js
CHANGED
|
@@ -4,7 +4,7 @@ const { posix: { resolve } } = require( "path" );
|
|
|
4
4
|
|
|
5
5
|
module.exports = function() {
|
|
6
6
|
const api = this;
|
|
7
|
-
const {
|
|
7
|
+
const { services: Services, models: Models, utility: { case: Case } } = api;
|
|
8
8
|
|
|
9
9
|
const logDebug = api.log( "hitchy:odem:rest:debug" );
|
|
10
10
|
const logError = api.log( "hitchy:odem:rest:error" );
|
|
@@ -23,10 +23,6 @@ module.exports = function() {
|
|
|
23
23
|
before.set( `ALL ${resolve( urlPrefix, ".schema" )}`, CORS.getRequestFilterForSchemata() );
|
|
24
24
|
after.set( `ALL ${resolve( urlPrefix, ".schema" )}`, reqNotSupported );
|
|
25
25
|
|
|
26
|
-
if ( api.plugins.authentication ) {
|
|
27
|
-
before.set( `GET ${resolve( urlPrefix, ".schema" )}`, Services.AuthorizationPolicyGenerator.mayAccess( "@hitchy.odem.schema" ) );
|
|
28
|
-
}
|
|
29
|
-
|
|
30
26
|
for ( let i = 0, numNames = modelNames.length; i < numNames; i++ ) {
|
|
31
27
|
const name = modelNames[i];
|
|
32
28
|
const routeName = Case.pascalToKebab( name );
|
|
@@ -36,55 +32,6 @@ module.exports = function() {
|
|
|
36
32
|
before.set( `ALL ${resolve( urlPrefix, routeName, ".schema" )}`, CORS.getRequestFilterForModelSchema( model ) );
|
|
37
33
|
before.set( `ALL ${resolve( urlPrefix, routeName, ":uuid" )}`, CORS.getRequestFilterForModelItem( model ) );
|
|
38
34
|
|
|
39
|
-
if ( api.plugins.authentication ) {
|
|
40
|
-
// add policies for additionally checking a requesting user's authorization
|
|
41
|
-
const modelUrl = resolve( urlPrefix, routeName );
|
|
42
|
-
const policy = action => Services.AuthorizationPolicyGenerator.mayAccess( `@hitchy.odem.model.${name}.${action}` );
|
|
43
|
-
|
|
44
|
-
const handlers = {
|
|
45
|
-
schema: policy( "schema" ),
|
|
46
|
-
create: policy( "create" ),
|
|
47
|
-
list: policy( "list" ),
|
|
48
|
-
read: policy( "read" ),
|
|
49
|
-
write: policy( "write" ),
|
|
50
|
-
check: policy( "check" ),
|
|
51
|
-
remove: policy( "remove" ),
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
// convenience routes
|
|
55
|
-
before.set( `GET ${resolve( modelUrl, "create" )}`, handlers.create );
|
|
56
|
-
before.set( `GET ${resolve( modelUrl, "write", ":uuid" )}`, handlers.write );
|
|
57
|
-
before.set( `GET ${resolve( modelUrl, "replace", ":uuid" )}`, handlers.write );
|
|
58
|
-
before.set( `GET ${resolve( modelUrl, "has", ":uuid" )}`, handlers.check );
|
|
59
|
-
before.set( `GET ${resolve( modelUrl, "remove", ":uuid" )}`, handlers.remove );
|
|
60
|
-
|
|
61
|
-
// extended routes
|
|
62
|
-
before.set( `GET ${resolve( modelUrl, ".schema" )}`, policy( "schema" ) );
|
|
63
|
-
|
|
64
|
-
// REST-compliant routes
|
|
65
|
-
before.set( `GET ${modelUrl}`, function( req, res, next ) {
|
|
66
|
-
const tail = req.url.substring( modelUrl.length ).trim();
|
|
67
|
-
|
|
68
|
-
if ( tail && tail !== "/" ) {
|
|
69
|
-
next();
|
|
70
|
-
} else {
|
|
71
|
-
handlers.list.call( this, req, res, next );
|
|
72
|
-
}
|
|
73
|
-
} );
|
|
74
|
-
before.set( `POST ${resolve( modelUrl )}`, handlers.create );
|
|
75
|
-
before.set( `GET ${resolve( modelUrl, ":uuid" )}`, ( req, res, next ) => {
|
|
76
|
-
if ( req.params.uuid === ".schema" ) {
|
|
77
|
-
next();
|
|
78
|
-
} else {
|
|
79
|
-
handlers.read.call( this, req, res, next );
|
|
80
|
-
}
|
|
81
|
-
} );
|
|
82
|
-
before.set( `PATCH ${resolve( modelUrl, ":uuid" )}`, handlers.write );
|
|
83
|
-
before.set( `PUT ${resolve( modelUrl, ":uuid" )}`, handlers.write );
|
|
84
|
-
before.set( `HEAD ${resolve( modelUrl, ":uuid" )}`, handlers.check );
|
|
85
|
-
before.set( `DELETE ${resolve( modelUrl, ":uuid" )}`, handlers.remove );
|
|
86
|
-
}
|
|
87
|
-
|
|
88
35
|
after.set( `ALL ${resolve( urlPrefix, routeName )}`, reqNotSupported );
|
|
89
36
|
}
|
|
90
37
|
|
|
@@ -123,7 +70,7 @@ module.exports = function() {
|
|
|
123
70
|
const routeName = Case.pascalToKebab( name );
|
|
124
71
|
const model = Models[name] || {};
|
|
125
72
|
|
|
126
|
-
addRoutesOnModel( routes, urlPrefix, routeName, model, convenience );
|
|
73
|
+
addRoutesOnModel( routes, urlPrefix, routeName, name, model, convenience );
|
|
127
74
|
}
|
|
128
75
|
|
|
129
76
|
routes.set( "HEAD " + resolve( urlPrefix, ":model" ), ( _, res ) => res.status( 404 ).send() );
|
|
@@ -133,6 +80,20 @@ module.exports = function() {
|
|
|
133
80
|
},
|
|
134
81
|
};
|
|
135
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Generates JSON response indicating rejection of access.
|
|
85
|
+
*
|
|
86
|
+
* @param {Hitchy.Core.ServerResponse} res response manager
|
|
87
|
+
* @returns {void}
|
|
88
|
+
*/
|
|
89
|
+
function resAccessForbidden( res ) {
|
|
90
|
+
res
|
|
91
|
+
.status( 403 )
|
|
92
|
+
.json( {
|
|
93
|
+
error: "access forbidden",
|
|
94
|
+
} );
|
|
95
|
+
}
|
|
96
|
+
|
|
136
97
|
/**
|
|
137
98
|
* Adds routes handling common requests not related to particular model.
|
|
138
99
|
*
|
|
@@ -143,7 +104,7 @@ module.exports = function() {
|
|
|
143
104
|
* @returns {void}
|
|
144
105
|
*/
|
|
145
106
|
function addGlobalRoutes( routes, urlPrefix, models ) {
|
|
146
|
-
const {
|
|
107
|
+
const { services: { Model: BaseModel, OdemSchema }, utility: { case: { pascalToKebab } } } = api;
|
|
147
108
|
|
|
148
109
|
routes.set( `GET ${resolve( urlPrefix, ".schema" )}`, reqFetchSchemata );
|
|
149
110
|
|
|
@@ -154,7 +115,12 @@ module.exports = function() {
|
|
|
154
115
|
* @param {Hitchy.Core.ServerResponse} res response manager
|
|
155
116
|
* @returns {void}
|
|
156
117
|
*/
|
|
157
|
-
function reqFetchSchemata( req, res ) {
|
|
118
|
+
async function reqFetchSchemata( req, res ) {
|
|
119
|
+
if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, "@hitchy.odem.schema" ) ) {
|
|
120
|
+
resAccessForbidden( res );
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
158
124
|
const modelKeys = Object.keys( models );
|
|
159
125
|
const numModels = modelKeys.length;
|
|
160
126
|
|
|
@@ -183,11 +149,12 @@ module.exports = function() {
|
|
|
183
149
|
* route patterns into function handling requests matching that pattern
|
|
184
150
|
* @param {string} urlPrefix common prefix to use on every route regarding any model-related processing
|
|
185
151
|
* @param {string} routeName name of model to be used in path name of request
|
|
152
|
+
* @param {string} modelName name of model derived from name extracted from path name of request in `routeName`
|
|
186
153
|
* @param {class<Model>} Model model class
|
|
187
154
|
* @param {boolean} includeConvenienceRoutes set true to include additional set of routes for controlling all action via GET-requests
|
|
188
155
|
* @returns {void}
|
|
189
156
|
*/
|
|
190
|
-
function addRoutesOnModel( routes, urlPrefix, routeName, Model, includeConvenienceRoutes ) {
|
|
157
|
+
function addRoutesOnModel( routes, urlPrefix, routeName, modelName, Model, includeConvenienceRoutes ) {
|
|
191
158
|
const { Model: BaseModel, OdemSchema: Schema, OdemUtilityUuid: { ptnUuid } } = Services;
|
|
192
159
|
|
|
193
160
|
const modelUrl = resolve( urlPrefix, routeName );
|
|
@@ -262,9 +229,14 @@ module.exports = function() {
|
|
|
262
229
|
* @param {Hitchy.Core.ServerResponse} res API for creating response
|
|
263
230
|
* @returns {void}
|
|
264
231
|
*/
|
|
265
|
-
function reqFetchSchema( req, res ) {
|
|
232
|
+
async function reqFetchSchema( req, res ) {
|
|
266
233
|
logDebug( "got request fetching schema" );
|
|
267
234
|
|
|
235
|
+
if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.schema` ) ) {
|
|
236
|
+
resAccessForbidden( res );
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
268
240
|
if ( !Services.OdemSchema.mayBeExposed( req, Model ) ) {
|
|
269
241
|
res.status( 403 ).json( { error: "access forbidden by model" } );
|
|
270
242
|
return;
|
|
@@ -281,23 +253,28 @@ module.exports = function() {
|
|
|
281
253
|
* @param {Hitchy.Core.ServerResponse} res API for creating response
|
|
282
254
|
* @returns {Promise|undefined} promises request processed successfully
|
|
283
255
|
*/
|
|
284
|
-
function reqCheckItem( req, res ) {
|
|
256
|
+
async function reqCheckItem( req, res ) {
|
|
285
257
|
logDebug( "got request checking if some item exists" );
|
|
286
258
|
|
|
259
|
+
if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.check` ) ) {
|
|
260
|
+
resAccessForbidden( res );
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
287
264
|
if ( !Schema.mayBeExposed( req, Model ) ) {
|
|
288
265
|
res.status( 403 ).json( { error: "access forbidden by model" } );
|
|
289
|
-
return
|
|
266
|
+
return;
|
|
290
267
|
}
|
|
291
268
|
|
|
292
269
|
const { uuid } = req.params;
|
|
293
270
|
if ( !ptnUuid.test( uuid ) ) {
|
|
294
271
|
res.status( 400 ).send();
|
|
295
|
-
return
|
|
272
|
+
return;
|
|
296
273
|
}
|
|
297
274
|
|
|
298
275
|
const item = new Model( uuid ); // eslint-disable-line new-cap
|
|
299
276
|
|
|
300
|
-
|
|
277
|
+
await item.$exists
|
|
301
278
|
.then( exists => {
|
|
302
279
|
res.status( exists ? 200 : 404 ).send();
|
|
303
280
|
} )
|
|
@@ -312,25 +289,30 @@ module.exports = function() {
|
|
|
312
289
|
*
|
|
313
290
|
* @param {Hitchy.Core.IncomingMessage} req description of request
|
|
314
291
|
* @param {Hitchy.Core.ServerResponse} res API for creating response
|
|
315
|
-
* @returns {Promise} promises request processed successfully
|
|
292
|
+
* @returns {Promise<void>} promises request processed successfully
|
|
316
293
|
*/
|
|
317
|
-
function reqFetchItem( req, res ) {
|
|
294
|
+
async function reqFetchItem( req, res ) {
|
|
318
295
|
logDebug( "got request fetching some item" );
|
|
319
296
|
|
|
297
|
+
if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.read` ) ) {
|
|
298
|
+
resAccessForbidden( res );
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
320
302
|
if ( !Schema.mayBeExposed( req, Model ) ) {
|
|
321
303
|
res.status( 403 ).json( { error: "access forbidden by model" } );
|
|
322
|
-
return
|
|
304
|
+
return;
|
|
323
305
|
}
|
|
324
306
|
|
|
325
307
|
const { uuid } = req.params;
|
|
326
308
|
if ( !ptnUuid.test( uuid ) ) {
|
|
327
309
|
res.status( 400 ).json( { error: "invalid UUID" } );
|
|
328
|
-
return
|
|
310
|
+
return;
|
|
329
311
|
}
|
|
330
312
|
|
|
331
313
|
const item = new Model( uuid ); // eslint-disable-line new-cap
|
|
332
314
|
|
|
333
|
-
|
|
315
|
+
await item.load()
|
|
334
316
|
.then( loaded => res.json( Schema.filterItem( loaded.toObject( { serialized: true } ), req, Model, "read" ) ) )
|
|
335
317
|
.catch( error => {
|
|
336
318
|
logError( "fetching %s:", routeName, error );
|
|
@@ -340,6 +322,7 @@ module.exports = function() {
|
|
|
340
322
|
res.status( 404 ).json( { error: "selected item not found" } );
|
|
341
323
|
break;
|
|
342
324
|
}
|
|
325
|
+
|
|
343
326
|
default : {
|
|
344
327
|
res.status( 500 ).json( { error: error.message } );
|
|
345
328
|
}
|
|
@@ -355,17 +338,22 @@ module.exports = function() {
|
|
|
355
338
|
* @param {Hitchy.Core.ServerResponse} res response controller
|
|
356
339
|
* @returns {Promise} promises response sent
|
|
357
340
|
*/
|
|
358
|
-
function reqFetchItems( req, res ) {
|
|
341
|
+
async function reqFetchItems( req, res ) {
|
|
359
342
|
logDebug( "got request fetching items" );
|
|
360
343
|
|
|
344
|
+
if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.list` ) ) {
|
|
345
|
+
resAccessForbidden( res );
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
361
349
|
if ( !Schema.mayBeExposed( req, Model ) ) {
|
|
362
350
|
res.status( 403 ).json( { error: "access forbidden by model" } );
|
|
363
|
-
return
|
|
351
|
+
return;
|
|
364
352
|
}
|
|
365
353
|
|
|
366
354
|
if ( req.headers["x-list-as-array"] ) {
|
|
367
355
|
res.status( 400 ).json( { error: "fetching items as array is deprecated for security reasons" } );
|
|
368
|
-
return
|
|
356
|
+
return;
|
|
369
357
|
}
|
|
370
358
|
|
|
371
359
|
let handler = reqListAll;
|
|
@@ -374,7 +362,7 @@ module.exports = function() {
|
|
|
374
362
|
handler = reqListMatches;
|
|
375
363
|
}
|
|
376
364
|
|
|
377
|
-
|
|
365
|
+
await handler.call( this, req, res );
|
|
378
366
|
}
|
|
379
367
|
|
|
380
368
|
/**
|
|
@@ -505,17 +493,18 @@ module.exports = function() {
|
|
|
505
493
|
* @param {Hitchy.Core.ServerResponse} res API for creating response
|
|
506
494
|
* @returns {Promise|undefined} promises request processed successfully
|
|
507
495
|
*/
|
|
508
|
-
function reqListAll( req, res ) {
|
|
496
|
+
async function reqListAll( req, res ) {
|
|
509
497
|
logDebug( "got request listing all items" );
|
|
510
498
|
|
|
511
499
|
if ( !Schema.mayBeExposed( req, Model ) ) {
|
|
512
500
|
res.status( 403 ).json( { error: "access forbidden by model" } );
|
|
513
|
-
return
|
|
501
|
+
return;
|
|
514
502
|
}
|
|
515
503
|
|
|
516
504
|
const { offset = 0, limit = Infinity, sortBy = null, descending = false, loadRecords = true, count = false } = req.query;
|
|
517
505
|
const meta = count || req.headers["x-count"] ? {} : null;
|
|
518
|
-
|
|
506
|
+
|
|
507
|
+
await Model.list( {
|
|
519
508
|
offset,
|
|
520
509
|
limit,
|
|
521
510
|
sortBy,
|
|
@@ -547,17 +536,22 @@ module.exports = function() {
|
|
|
547
536
|
* @param {Hitchy.Core.ServerResponse} res API for creating response
|
|
548
537
|
* @returns {Promise|undefined} promises request processed successfully
|
|
549
538
|
*/
|
|
550
|
-
function reqCreateItem( req, res ) {
|
|
539
|
+
async function reqCreateItem( req, res ) {
|
|
551
540
|
logDebug( "got request creating item" );
|
|
552
541
|
|
|
542
|
+
if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.create` ) ) {
|
|
543
|
+
resAccessForbidden( res );
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
|
|
553
547
|
if ( !Schema.mayBeExposed( req, Model ) ) {
|
|
554
548
|
res.status( 403 ).json( { error: "access forbidden by model" } );
|
|
555
|
-
return
|
|
549
|
+
return;
|
|
556
550
|
}
|
|
557
551
|
|
|
558
552
|
const item = new Model(); // eslint-disable-line new-cap
|
|
559
553
|
|
|
560
|
-
|
|
554
|
+
await ( req.method === "GET" ? Promise.resolve( req.query ) : req.fetchBody() )
|
|
561
555
|
.then( record => {
|
|
562
556
|
if ( record ) {
|
|
563
557
|
if ( record.uuid ) {
|
|
@@ -595,23 +589,28 @@ module.exports = function() {
|
|
|
595
589
|
* @param {Hitchy.Core.ServerResponse} res API for creating response
|
|
596
590
|
* @returns {Promise|undefined} promises request processed successfully
|
|
597
591
|
*/
|
|
598
|
-
function reqModifyItem( req, res ) {
|
|
592
|
+
async function reqModifyItem( req, res ) {
|
|
599
593
|
logDebug( "got request to modify some item" );
|
|
600
594
|
|
|
595
|
+
if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.write` ) ) {
|
|
596
|
+
resAccessForbidden( res );
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
|
|
601
600
|
if ( !Schema.mayBeExposed( req, Model ) ) {
|
|
602
601
|
res.status( 403 ).json( { error: "access forbidden by model" } );
|
|
603
|
-
return
|
|
602
|
+
return;
|
|
604
603
|
}
|
|
605
604
|
|
|
606
605
|
const { uuid } = req.params;
|
|
607
606
|
if ( !ptnUuid.test( uuid ) ) {
|
|
608
607
|
res.status( 400 ).json( { error: "invalid UUID" } );
|
|
609
|
-
return
|
|
608
|
+
return;
|
|
610
609
|
}
|
|
611
610
|
|
|
612
611
|
const item = new Model( uuid ); // eslint-disable-line new-cap
|
|
613
612
|
|
|
614
|
-
|
|
613
|
+
await item.$exists
|
|
615
614
|
.then( exists => {
|
|
616
615
|
if ( !exists ) {
|
|
617
616
|
res.status( 404 ).json( { error: "selected item not found" } );
|
|
@@ -655,23 +654,28 @@ module.exports = function() {
|
|
|
655
654
|
* @param {Hitchy.Core.ServerResponse} res API for creating response
|
|
656
655
|
* @returns {Promise|undefined} promises request processed successfully
|
|
657
656
|
*/
|
|
658
|
-
function reqReplaceItem( req, res ) {
|
|
657
|
+
async function reqReplaceItem( req, res ) {
|
|
659
658
|
logDebug( "got request replacing some item" );
|
|
660
659
|
|
|
660
|
+
if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.write` ) ) {
|
|
661
|
+
resAccessForbidden( res );
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
|
|
661
665
|
if ( !Schema.mayBeExposed( req, Model ) ) {
|
|
662
666
|
res.status( 403 ).json( { error: "access forbidden by model" } );
|
|
663
|
-
return
|
|
667
|
+
return;
|
|
664
668
|
}
|
|
665
669
|
|
|
666
670
|
const { uuid } = req.params;
|
|
667
671
|
if ( !ptnUuid.test( uuid ) ) {
|
|
668
672
|
res.status( 400 ).json( { error: "invalid UUID" } );
|
|
669
|
-
return
|
|
673
|
+
return;
|
|
670
674
|
}
|
|
671
675
|
|
|
672
676
|
const item = new Model( uuid, { onUnsaved: false } ); // eslint-disable-line new-cap
|
|
673
677
|
|
|
674
|
-
|
|
678
|
+
await Promise.all( [ item.$exists, req.method === "GET" ? Promise.resolve( req.query ) : req.fetchBody() ] )
|
|
675
679
|
.then( ( [ exists, record ] ) => {
|
|
676
680
|
return ( exists ? item.load() : Promise.resolve() ).then( () => {
|
|
677
681
|
const propNames = Object.keys( Model.schema.props );
|
|
@@ -714,23 +718,28 @@ module.exports = function() {
|
|
|
714
718
|
* @param {Hitchy.Core.ServerResponse} res API for creating response
|
|
715
719
|
* @returns {Promise|undefined} promises request processed successfully
|
|
716
720
|
*/
|
|
717
|
-
function reqRemoveItem( req, res ) {
|
|
721
|
+
async function reqRemoveItem( req, res ) {
|
|
718
722
|
logDebug( "got request removing some item" );
|
|
719
723
|
|
|
724
|
+
if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.remove` ) ) {
|
|
725
|
+
resAccessForbidden( res );
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
|
|
720
729
|
if ( !Schema.mayBeExposed( req, Model ) ) {
|
|
721
730
|
res.status( 403 ).json( { error: "access forbidden by model" } );
|
|
722
|
-
return
|
|
731
|
+
return;
|
|
723
732
|
}
|
|
724
733
|
|
|
725
734
|
const { uuid } = req.params;
|
|
726
735
|
if ( !ptnUuid.test( uuid ) ) {
|
|
727
736
|
res.status( 400 ).json( { error: "invalid UUID" } );
|
|
728
|
-
return
|
|
737
|
+
return;
|
|
729
738
|
}
|
|
730
739
|
|
|
731
740
|
const item = new Model( uuid ); // eslint-disable-line new-cap
|
|
732
741
|
|
|
733
|
-
|
|
742
|
+
await item.$exists
|
|
734
743
|
.then( exists => {
|
|
735
744
|
if ( exists ) {
|
|
736
745
|
return item.remove()
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hitchy/plugin-odem-rest",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "HTTP REST API for Hitchy's
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "HTTP REST API for Hitchy's document-oriented database",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"lint": "eslint .",
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"repository": "https://gitlab.com/hitchy/plugin-odem-rest.git",
|
|
11
11
|
"keywords": [
|
|
12
|
-
"hitchy"
|
|
13
|
-
"ODM"
|
|
12
|
+
"hitchy"
|
|
14
13
|
],
|
|
15
14
|
"author": "Thomas Urban",
|
|
16
15
|
"license": "MIT",
|
|
@@ -18,7 +17,7 @@
|
|
|
18
17
|
"homepage": "https://gitlab.com/hitchy/plugin-odem-rest#plugin-odem-rest",
|
|
19
18
|
"peerDependencies": {
|
|
20
19
|
"@hitchy/core": "0.8.x",
|
|
21
|
-
"@hitchy/plugin-odem": "0.
|
|
20
|
+
"@hitchy/plugin-odem": "0.9.x",
|
|
22
21
|
"@hitchy/plugin-auth": "0.4.x"
|
|
23
22
|
},
|
|
24
23
|
"devDependencies": {
|
|
@@ -27,8 +26,8 @@
|
|
|
27
26
|
"c8": "^10.1.2",
|
|
28
27
|
"eslint": "^8.57.0",
|
|
29
28
|
"eslint-config-cepharum": "^1.0.14",
|
|
30
|
-
"eslint-plugin-promise": "^6.
|
|
31
|
-
"mocha": "^10.7.
|
|
29
|
+
"eslint-plugin-promise": "^6.6.0",
|
|
30
|
+
"mocha": "^10.7.3",
|
|
32
31
|
"should": "^13.2.3",
|
|
33
32
|
"should-http": "^0.1.1"
|
|
34
33
|
}
|
package/readme.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# plugin-odem-rest [](https://gitlab.com/hitchy/plugin-odem-rest/-/commits/master)
|
|
2
2
|
|
|
3
|
-
HTTP REST API for [Hitchy's](https://core.hitchy.org/) [
|
|
3
|
+
HTTP REST API for [Hitchy's](https://core.hitchy.org/) [document-oriented database](https://odem.hitchy.org/)
|
|
4
4
|
|
|
5
|
-
[Hitchy](http://core.hitchy.org/) is a server-side framework for developing web applications with [Node.js](https://nodejs.org/). [Odem](https://www.npmjs.com/package/@hitchy/plugin-odem) is plugin for Hitchy implementing
|
|
5
|
+
[Hitchy](http://core.hitchy.org/) is a server-side framework for developing web applications with [Node.js](https://nodejs.org/). [Odem](https://www.npmjs.com/package/@hitchy/plugin-odem) is a plugin for Hitchy implementing a document-oriented database using data backends like regular file systems, LevelDBs and temporary in-memory databases.
|
|
6
6
|
|
|
7
|
-
This plugin is defining blueprint routes for accessing data managed in
|
|
7
|
+
This plugin is defining blueprint routes for accessing data managed in document-oriented database using REST API.
|
|
8
8
|
|
|
9
9
|
## License
|
|
10
10
|
|
|
@@ -44,7 +44,7 @@ exports.auth = {
|
|
|
44
44
|
|
|
45
45
|
> **Do not use this in a production setup!**
|
|
46
46
|
>
|
|
47
|
-
> This example is granting permissions to create, adjust and remove items of your
|
|
47
|
+
> This example is granting permissions to create, adjust and remove items of your document-oriented database without any authentication. In addition, all _protected_ models and properties get exposed to everyone.
|
|
48
48
|
>
|
|
49
49
|
> See the [section on authorization](#authorization) for additional information!
|
|
50
50
|
|
|
@@ -105,7 +105,7 @@ exports.model = {
|
|
|
105
105
|
|
|
106
106
|
The model's segment in URL `<model>` is derived as the kebab-case version of model's name which is given in PascalCase. Thus, a model definition in a file named **api/models/my-fancy-model.js** is assumed to describe a model named **MyFancyModel** by default, resulting in model's URL segment to be **my-fancy-model** again. So the URL path for the collection of items is `/api/my-fancy-model`.
|
|
107
107
|
|
|
108
|
-
In Hitchy's
|
|
108
|
+
In Hitchy's document-oriented database all model instances or items are uniquely addressable via UUIDs. By appending an item's UUID to the given URL path of a collection you get the URL path of that item, e.g. `/api/my-fancy-model/01234567-1234-1234-1234-56789abcdef0`.
|
|
109
109
|
|
|
110
110
|
|
|
111
111
|
### The REST API
|
|
@@ -220,9 +220,9 @@ For example, a GET-request for `/api/localEmployee?q=salary:between:2000:4000` w
|
|
|
220
220
|
|
|
221
221
|
##### Complex tests <Bade type=info text=v0.5.2+></Badge>
|
|
222
222
|
|
|
223
|
-
Hitchy
|
|
223
|
+
Hitchy's document-oriented database supports more complex queries that can't be encoded as such simple queries as described above. Thus, a different way of querying has been added.
|
|
224
224
|
|
|
225
|
-
When using parameter `query` instead of `q`, its value is assumed to be a JSON-encoded query complying with query syntax supported by [Model.find() method of Hitchy
|
|
225
|
+
When using parameter `query` instead of `q`, its value is assumed to be a JSON-encoded query complying with query syntax supported by [Model.find() method of Hitchy's document-oriented database](https://odem.hitchy.org/api/model.html#model-find).
|
|
226
226
|
|
|
227
227
|
```http request
|
|
228
228
|
GET /api/user?query={"in":{"name":["john","jane","jason"]}}
|
|
@@ -272,7 +272,7 @@ Resources are declared to control authorizations for basically interacting with
|
|
|
272
272
|
* When creating a new item, accessing the resource `@hitchy.odem.model.<ModelName>.create` must be granted.
|
|
273
273
|
* When removing an item, accessing the resource `@hitchy.odem.model.<ModelName>.remove` must be granted.
|
|
274
274
|
* Accessing a model's schema requires the resource `@hitchy.odem.model.<ModelName>.schema` to be granted.
|
|
275
|
-
* Accessing the collection of all models' schemata requires the resource `@hitchy.odem.schema` to be granted. This implicitly causes models with their [promote option](https://odem.hitchy.org/guides/defining-models.html#options) being `protected` to be exposed in responses to that request unless
|
|
275
|
+
* Accessing the collection of all models' schemata requires the resource `@hitchy.odem.schema` to be granted. This implicitly causes models with their [promote option](https://odem.hitchy.org/guides/defining-models.html#options) being `protected` to be exposed in responses to that request unless resource `@hitchy.odem.model.<ModelName>.promote` isn't revoked from the user.
|
|
276
276
|
|
|
277
277
|
> In these examples, replace `<ModelName>` with a model's name in PascalCase.
|
|
278
278
|
|