@hitchy/plugin-odem-rest 0.6.0 → 0.7.1

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  module.exports = function() {
4
4
  const Config = this.config;
5
- const Services = this.runtime.services;
5
+ const Services = this.services;
6
6
 
7
7
  const CommonlyAcceptedHeaders = [
8
8
  "Accept", "Accept-Language", "Authorization", "Content-Language",
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 { runtime: { services: Services, models: Models }, utility: { case: Case } } = api;
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 { runtime: { services: { Model: BaseModel, OdemSchema } }, utility: { case: { pascalToKebab } } } = api;
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 );
@@ -235,7 +202,7 @@ module.exports = function() {
235
202
  * @returns {void}
236
203
  */
237
204
  function reqSuccess( req, res ) {
238
- if ( Services.OdemSchema.mayBeExposed( req, Model ) ) {
205
+ if ( Schema.mayBeExposed( req, Model ) ) {
239
206
  res.status( 200 ).send();
240
207
  } else {
241
208
  res.status( 403 ).send();
@@ -262,14 +229,19 @@ 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
 
268
- if ( !Services.OdemSchema.mayBeExposed( req, Model ) ) {
235
+ if ( !Schema.mayBeExposed( req, Model ) ) {
269
236
  res.status( 403 ).json( { error: "access forbidden by model" } );
270
237
  return;
271
238
  }
272
239
 
240
+ if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.schema` ) ) {
241
+ resAccessForbidden( res );
242
+ return;
243
+ }
244
+
273
245
  res.json( Schema.extractPublicData( Model ) );
274
246
  }
275
247
 
@@ -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
 
287
259
  if ( !Schema.mayBeExposed( req, Model ) ) {
288
260
  res.status( 403 ).json( { error: "access forbidden by model" } );
289
- return undefined;
261
+ return;
262
+ }
263
+
264
+ if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.check` ) ) {
265
+ resAccessForbidden( res );
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 undefined;
272
+ return;
296
273
  }
297
274
 
298
275
  const item = new Model( uuid ); // eslint-disable-line new-cap
299
276
 
300
- return item.$exists
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
 
320
297
  if ( !Schema.mayBeExposed( req, Model ) ) {
321
298
  res.status( 403 ).json( { error: "access forbidden by model" } );
322
- return undefined;
299
+ return;
300
+ }
301
+
302
+ if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.read` ) ) {
303
+ resAccessForbidden( res );
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 undefined;
310
+ return;
329
311
  }
330
312
 
331
313
  const item = new Model( uuid ); // eslint-disable-line new-cap
332
314
 
333
- return item.load()
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
 
361
344
  if ( !Schema.mayBeExposed( req, Model ) ) {
362
345
  res.status( 403 ).json( { error: "access forbidden by model" } );
363
- return undefined;
346
+ return;
347
+ }
348
+
349
+ if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.list` ) ) {
350
+ resAccessForbidden( res );
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 undefined;
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
- return handler.call( this, req, res );
365
+ await handler.call( this, req, res );
378
366
  }
379
367
 
380
368
  /**
@@ -418,11 +406,6 @@ module.exports = function() {
418
406
  async function reqListMatches( req, res ) {
419
407
  logDebug( "got request listing matching items" );
420
408
 
421
- if ( !Schema.mayBeExposed( req, Model ) ) {
422
- res.status( 403 ).json( { error: "access forbidden by model" } );
423
- return;
424
- }
425
-
426
409
  const {
427
410
  q: simpleQuery = "",
428
411
  offset = 0,
@@ -505,17 +488,13 @@ module.exports = function() {
505
488
  * @param {Hitchy.Core.ServerResponse} res API for creating response
506
489
  * @returns {Promise|undefined} promises request processed successfully
507
490
  */
508
- function reqListAll( req, res ) {
491
+ async function reqListAll( req, res ) {
509
492
  logDebug( "got request listing all items" );
510
493
 
511
- if ( !Schema.mayBeExposed( req, Model ) ) {
512
- res.status( 403 ).json( { error: "access forbidden by model" } );
513
- return undefined;
514
- }
515
-
516
494
  const { offset = 0, limit = Infinity, sortBy = null, descending = false, loadRecords = true, count = false } = req.query;
517
495
  const meta = count || req.headers["x-count"] ? {} : null;
518
- return Model.list( {
496
+
497
+ await Model.list( {
519
498
  offset,
520
499
  limit,
521
500
  sortBy,
@@ -547,17 +526,22 @@ module.exports = function() {
547
526
  * @param {Hitchy.Core.ServerResponse} res API for creating response
548
527
  * @returns {Promise|undefined} promises request processed successfully
549
528
  */
550
- function reqCreateItem( req, res ) {
529
+ async function reqCreateItem( req, res ) {
551
530
  logDebug( "got request creating item" );
552
531
 
553
532
  if ( !Schema.mayBeExposed( req, Model ) ) {
554
533
  res.status( 403 ).json( { error: "access forbidden by model" } );
555
- return undefined;
534
+ return;
535
+ }
536
+
537
+ if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.create` ) ) {
538
+ resAccessForbidden( res );
539
+ return;
556
540
  }
557
541
 
558
542
  const item = new Model(); // eslint-disable-line new-cap
559
543
 
560
- return ( req.method === "GET" ? Promise.resolve( req.query ) : req.fetchBody() )
544
+ await ( req.method === "GET" ? Promise.resolve( req.query ) : req.fetchBody() )
561
545
  .then( record => {
562
546
  if ( record ) {
563
547
  if ( record.uuid ) {
@@ -595,23 +579,28 @@ module.exports = function() {
595
579
  * @param {Hitchy.Core.ServerResponse} res API for creating response
596
580
  * @returns {Promise|undefined} promises request processed successfully
597
581
  */
598
- function reqModifyItem( req, res ) {
582
+ async function reqModifyItem( req, res ) {
599
583
  logDebug( "got request to modify some item" );
600
584
 
601
585
  if ( !Schema.mayBeExposed( req, Model ) ) {
602
586
  res.status( 403 ).json( { error: "access forbidden by model" } );
603
- return undefined;
587
+ return;
588
+ }
589
+
590
+ if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.write` ) ) {
591
+ resAccessForbidden( res );
592
+ return;
604
593
  }
605
594
 
606
595
  const { uuid } = req.params;
607
596
  if ( !ptnUuid.test( uuid ) ) {
608
597
  res.status( 400 ).json( { error: "invalid UUID" } );
609
- return undefined;
598
+ return;
610
599
  }
611
600
 
612
601
  const item = new Model( uuid ); // eslint-disable-line new-cap
613
602
 
614
- return item.$exists
603
+ await item.$exists
615
604
  .then( exists => {
616
605
  if ( !exists ) {
617
606
  res.status( 404 ).json( { error: "selected item not found" } );
@@ -655,23 +644,28 @@ module.exports = function() {
655
644
  * @param {Hitchy.Core.ServerResponse} res API for creating response
656
645
  * @returns {Promise|undefined} promises request processed successfully
657
646
  */
658
- function reqReplaceItem( req, res ) {
647
+ async function reqReplaceItem( req, res ) {
659
648
  logDebug( "got request replacing some item" );
660
649
 
661
650
  if ( !Schema.mayBeExposed( req, Model ) ) {
662
651
  res.status( 403 ).json( { error: "access forbidden by model" } );
663
- return undefined;
652
+ return;
653
+ }
654
+
655
+ if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.write` ) ) {
656
+ resAccessForbidden( res );
657
+ return;
664
658
  }
665
659
 
666
660
  const { uuid } = req.params;
667
661
  if ( !ptnUuid.test( uuid ) ) {
668
662
  res.status( 400 ).json( { error: "invalid UUID" } );
669
- return undefined;
663
+ return;
670
664
  }
671
665
 
672
666
  const item = new Model( uuid, { onUnsaved: false } ); // eslint-disable-line new-cap
673
667
 
674
- return Promise.all( [ item.$exists, req.method === "GET" ? Promise.resolve( req.query ) : req.fetchBody() ] )
668
+ await Promise.all( [ item.$exists, req.method === "GET" ? Promise.resolve( req.query ) : req.fetchBody() ] )
675
669
  .then( ( [ exists, record ] ) => {
676
670
  return ( exists ? item.load() : Promise.resolve() ).then( () => {
677
671
  const propNames = Object.keys( Model.schema.props );
@@ -714,23 +708,28 @@ module.exports = function() {
714
708
  * @param {Hitchy.Core.ServerResponse} res API for creating response
715
709
  * @returns {Promise|undefined} promises request processed successfully
716
710
  */
717
- function reqRemoveItem( req, res ) {
711
+ async function reqRemoveItem( req, res ) {
718
712
  logDebug( "got request removing some item" );
719
713
 
720
714
  if ( !Schema.mayBeExposed( req, Model ) ) {
721
715
  res.status( 403 ).json( { error: "access forbidden by model" } );
722
- return undefined;
716
+ return;
717
+ }
718
+
719
+ if ( api.plugins.authentication && !await Services.Authorization.mayAccess( req.user, `@hitchy.odem.model.${modelName}.remove` ) ) {
720
+ resAccessForbidden( res );
721
+ return;
723
722
  }
724
723
 
725
724
  const { uuid } = req.params;
726
725
  if ( !ptnUuid.test( uuid ) ) {
727
726
  res.status( 400 ).json( { error: "invalid UUID" } );
728
- return undefined;
727
+ return;
729
728
  }
730
729
 
731
730
  const item = new Model( uuid ); // eslint-disable-line new-cap
732
731
 
733
- return item.$exists
732
+ await item.$exists
734
733
  .then( exists => {
735
734
  if ( exists ) {
736
735
  return item.remove()
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hitchy/plugin-odem-rest",
3
- "version": "0.6.0",
4
- "description": "HTTP REST API for Hitchy's ODM",
3
+ "version": "0.7.1",
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.8.x",
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.1.1",
31
- "mocha": "^10.7.0",
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 [![pipeline status](https://gitlab.com/hitchy/plugin-odem-rest/badges/master/pipeline.svg)](https://gitlab.com/hitchy/plugin-odem-rest/-/commits/master)
2
2
 
3
- HTTP REST API for [Hitchy's](https://core.hitchy.org/) [ODM](https://odem.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 an object document management (ODM) using data backends like regular file systems, LevelDBs and temporary in-memory databases.
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, temporary in-memory databases and third-party key-value stores.
6
6
 
7
- This plugin is defining blueprint routes for accessing data managed in ODM using REST API.
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 ODM without any authentication. In addition, all _protected_ models and properties get exposed to everyone.
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 ODM 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`.
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 ODM 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.
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 ODM](https://odem.hitchy.org/api/model.html#model-find).
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 a more specific resource `@hitchy.odem.schema.model.<ModelName>` isn't revoked from the user.
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