adapt-authoring-api 0.0.1 → 1.0.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/.eslintignore +1 -1
- package/.eslintrc +14 -14
- package/.github/ISSUE_TEMPLATE/bug_report.yml +55 -55
- package/.github/ISSUE_TEMPLATE/feature_request.yml +22 -22
- package/.github/dependabot.yml +11 -11
- package/.github/pull_request_template.md +25 -25
- package/.github/workflows/labelled_prs.yml +16 -16
- package/.github/workflows/new.yml +19 -19
- package/.github/workflows/releases.yml +25 -0
- package/adapt-authoring.json +9 -9
- package/conf/config.schema.json +22 -22
- package/docs/writing-an-api.md +135 -135
- package/errors/errors.json +31 -31
- package/index.js +7 -7
- package/lib/AbstractApiModule.js +668 -668
- package/lib/AbstractApiUtils.js +145 -145
- package/lib/DataCache.js +46 -46
- package/lib/typedefs.js +66 -66
- package/package.json +58 -23
- package/tests/abstractApiModule.spec.js +84 -84
- package/tests/abstractApiUtils.spec.js +49 -49
- package/tests/data/testApiModule.js +50 -50
package/lib/AbstractApiUtils.js
CHANGED
|
@@ -1,145 +1,145 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utilities for APIs
|
|
3
|
-
* @memberof api
|
|
4
|
-
*/
|
|
5
|
-
class AbstractApiUtils {
|
|
6
|
-
/**
|
|
7
|
-
* Converts HTTP methods to a corresponding 'action' for use in auth
|
|
8
|
-
* @param {String} method The HTTP method
|
|
9
|
-
* @return {String}
|
|
10
|
-
*/
|
|
11
|
-
static httpMethodToAction (method) {
|
|
12
|
-
switch (method.toLowerCase()) {
|
|
13
|
-
case 'get':
|
|
14
|
-
return 'read'
|
|
15
|
-
case 'post':
|
|
16
|
-
case 'put':
|
|
17
|
-
case 'patch':
|
|
18
|
-
case 'delete':
|
|
19
|
-
return 'write'
|
|
20
|
-
default:
|
|
21
|
-
return ''
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Converts HTTP methods to a corresponding database function
|
|
27
|
-
* @param {String} method The HTTP method
|
|
28
|
-
* @return {String}
|
|
29
|
-
*/
|
|
30
|
-
static httpMethodToDBFunction (method) {
|
|
31
|
-
switch (method.toLowerCase()) {
|
|
32
|
-
case 'post': return 'insert'
|
|
33
|
-
case 'get': return 'find'
|
|
34
|
-
case 'put': case 'patch': return 'update'
|
|
35
|
-
case 'delete': return 'delete'
|
|
36
|
-
default: return ''
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Generates a list of arguments to be passed to the MongoDBModule from a request object
|
|
42
|
-
* @param {external:ExpressRequest} req
|
|
43
|
-
* @return {Array<*>}
|
|
44
|
-
*/
|
|
45
|
-
static argsFromReq (req) {
|
|
46
|
-
const opts = { schemaName: req.apiData.schemaName, collectionName: req.apiData.collectionName }
|
|
47
|
-
switch (req.method) {
|
|
48
|
-
case 'GET': case 'DELETE':
|
|
49
|
-
return [req.apiData.query, opts]
|
|
50
|
-
case 'POST':
|
|
51
|
-
return [req.apiData.data, opts]
|
|
52
|
-
case 'PUT': case 'PATCH':
|
|
53
|
-
return [req.apiData.query, req.apiData.data, opts]
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Generates REST API metadata and stores on route config
|
|
59
|
-
* @param {AbstractApiModule} instance The current AbstractApiModule instance
|
|
60
|
-
*/
|
|
61
|
-
static generateApiMetadata (instance) {
|
|
62
|
-
const getData = isList => {
|
|
63
|
-
const $ref = { $ref: `#/components/schemas/${instance.schemaName}` }
|
|
64
|
-
return {
|
|
65
|
-
description: `The ${instance.schemaName} data`,
|
|
66
|
-
content: { 'application/json': { schema: isList ? { type: 'array', items: $ref } : $ref } }
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
const queryParams = [
|
|
70
|
-
{
|
|
71
|
-
name: 'limit',
|
|
72
|
-
in: 'query',
|
|
73
|
-
description: `How many results should be returned Default value is ${instance.app.config.get('adapt-authoring-api.defaultPageSize')} (max value is ${instance.app.config.get('adapt-authoring-api.maxPageSize')})`
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
name: 'page',
|
|
77
|
-
in: 'query',
|
|
78
|
-
description: 'The page of results to return (determined from the limit value)'
|
|
79
|
-
}
|
|
80
|
-
]
|
|
81
|
-
const verbMap = {
|
|
82
|
-
put: 'Replace',
|
|
83
|
-
get: 'Retrieve',
|
|
84
|
-
patch: 'Update',
|
|
85
|
-
delete: 'Delete',
|
|
86
|
-
post: 'Insert'
|
|
87
|
-
}
|
|
88
|
-
instance.routes.forEach(r => {
|
|
89
|
-
r.meta = {}
|
|
90
|
-
Object.keys(r.handlers).forEach(method => {
|
|
91
|
-
let summary, parameters, requestBody, responses
|
|
92
|
-
switch (r.route) {
|
|
93
|
-
case '/':
|
|
94
|
-
if (method === 'post') {
|
|
95
|
-
summary = `${verbMap.post} a new ${instance.schemaName} document`
|
|
96
|
-
requestBody = getData()
|
|
97
|
-
responses = { 201: getData() }
|
|
98
|
-
} else {
|
|
99
|
-
summary = `${verbMap.get} all ${instance.collectionName} documents`
|
|
100
|
-
parameters = queryParams
|
|
101
|
-
responses = { 200: getData(true) }
|
|
102
|
-
}
|
|
103
|
-
break
|
|
104
|
-
|
|
105
|
-
case '/:_id':
|
|
106
|
-
summary = `${verbMap[method]} an existing ${instance.schemaName} document`
|
|
107
|
-
requestBody = method === 'put' || method === 'patch' ? getData() : method === 'delete' ? undefined : {}
|
|
108
|
-
responses = { [method === 'delete' ? 204 : 200]: getData() }
|
|
109
|
-
break
|
|
110
|
-
|
|
111
|
-
case '/query':
|
|
112
|
-
summary = `Query all ${instance.collectionName}`
|
|
113
|
-
parameters = queryParams
|
|
114
|
-
responses = { 200: getData(true) }
|
|
115
|
-
break
|
|
116
|
-
|
|
117
|
-
case '/schema':
|
|
118
|
-
summary = `Retrieve ${instance.schemaName} schema`
|
|
119
|
-
break
|
|
120
|
-
}
|
|
121
|
-
r.meta[method] = { summary, parameters, requestBody, responses }
|
|
122
|
-
})
|
|
123
|
-
})
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Clones an object and converts any Dates and ObjectIds to Strings
|
|
128
|
-
* @param {Object} data
|
|
129
|
-
* @returns A clone object with stringified ObjectIds
|
|
130
|
-
*/
|
|
131
|
-
static stringifyValues (data) {
|
|
132
|
-
return Object.entries(data).reduce((cloned, [key, val]) => {
|
|
133
|
-
const type = val?.constructor?.name
|
|
134
|
-
cloned[key] =
|
|
135
|
-
type === 'Date' || type === 'ObjectId'
|
|
136
|
-
? val.toString()
|
|
137
|
-
: type === 'Array' || type === 'Object'
|
|
138
|
-
? this.stringifyValues(val)
|
|
139
|
-
: val
|
|
140
|
-
return cloned
|
|
141
|
-
}, Array.isArray(data) ? [] : {})
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export default AbstractApiUtils
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for APIs
|
|
3
|
+
* @memberof api
|
|
4
|
+
*/
|
|
5
|
+
class AbstractApiUtils {
|
|
6
|
+
/**
|
|
7
|
+
* Converts HTTP methods to a corresponding 'action' for use in auth
|
|
8
|
+
* @param {String} method The HTTP method
|
|
9
|
+
* @return {String}
|
|
10
|
+
*/
|
|
11
|
+
static httpMethodToAction (method) {
|
|
12
|
+
switch (method.toLowerCase()) {
|
|
13
|
+
case 'get':
|
|
14
|
+
return 'read'
|
|
15
|
+
case 'post':
|
|
16
|
+
case 'put':
|
|
17
|
+
case 'patch':
|
|
18
|
+
case 'delete':
|
|
19
|
+
return 'write'
|
|
20
|
+
default:
|
|
21
|
+
return ''
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Converts HTTP methods to a corresponding database function
|
|
27
|
+
* @param {String} method The HTTP method
|
|
28
|
+
* @return {String}
|
|
29
|
+
*/
|
|
30
|
+
static httpMethodToDBFunction (method) {
|
|
31
|
+
switch (method.toLowerCase()) {
|
|
32
|
+
case 'post': return 'insert'
|
|
33
|
+
case 'get': return 'find'
|
|
34
|
+
case 'put': case 'patch': return 'update'
|
|
35
|
+
case 'delete': return 'delete'
|
|
36
|
+
default: return ''
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Generates a list of arguments to be passed to the MongoDBModule from a request object
|
|
42
|
+
* @param {external:ExpressRequest} req
|
|
43
|
+
* @return {Array<*>}
|
|
44
|
+
*/
|
|
45
|
+
static argsFromReq (req) {
|
|
46
|
+
const opts = { schemaName: req.apiData.schemaName, collectionName: req.apiData.collectionName }
|
|
47
|
+
switch (req.method) {
|
|
48
|
+
case 'GET': case 'DELETE':
|
|
49
|
+
return [req.apiData.query, opts]
|
|
50
|
+
case 'POST':
|
|
51
|
+
return [req.apiData.data, opts]
|
|
52
|
+
case 'PUT': case 'PATCH':
|
|
53
|
+
return [req.apiData.query, req.apiData.data, opts]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Generates REST API metadata and stores on route config
|
|
59
|
+
* @param {AbstractApiModule} instance The current AbstractApiModule instance
|
|
60
|
+
*/
|
|
61
|
+
static generateApiMetadata (instance) {
|
|
62
|
+
const getData = isList => {
|
|
63
|
+
const $ref = { $ref: `#/components/schemas/${instance.schemaName}` }
|
|
64
|
+
return {
|
|
65
|
+
description: `The ${instance.schemaName} data`,
|
|
66
|
+
content: { 'application/json': { schema: isList ? { type: 'array', items: $ref } : $ref } }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const queryParams = [
|
|
70
|
+
{
|
|
71
|
+
name: 'limit',
|
|
72
|
+
in: 'query',
|
|
73
|
+
description: `How many results should be returned Default value is ${instance.app.config.get('adapt-authoring-api.defaultPageSize')} (max value is ${instance.app.config.get('adapt-authoring-api.maxPageSize')})`
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'page',
|
|
77
|
+
in: 'query',
|
|
78
|
+
description: 'The page of results to return (determined from the limit value)'
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
const verbMap = {
|
|
82
|
+
put: 'Replace',
|
|
83
|
+
get: 'Retrieve',
|
|
84
|
+
patch: 'Update',
|
|
85
|
+
delete: 'Delete',
|
|
86
|
+
post: 'Insert'
|
|
87
|
+
}
|
|
88
|
+
instance.routes.forEach(r => {
|
|
89
|
+
r.meta = {}
|
|
90
|
+
Object.keys(r.handlers).forEach(method => {
|
|
91
|
+
let summary, parameters, requestBody, responses
|
|
92
|
+
switch (r.route) {
|
|
93
|
+
case '/':
|
|
94
|
+
if (method === 'post') {
|
|
95
|
+
summary = `${verbMap.post} a new ${instance.schemaName} document`
|
|
96
|
+
requestBody = getData()
|
|
97
|
+
responses = { 201: getData() }
|
|
98
|
+
} else {
|
|
99
|
+
summary = `${verbMap.get} all ${instance.collectionName} documents`
|
|
100
|
+
parameters = queryParams
|
|
101
|
+
responses = { 200: getData(true) }
|
|
102
|
+
}
|
|
103
|
+
break
|
|
104
|
+
|
|
105
|
+
case '/:_id':
|
|
106
|
+
summary = `${verbMap[method]} an existing ${instance.schemaName} document`
|
|
107
|
+
requestBody = method === 'put' || method === 'patch' ? getData() : method === 'delete' ? undefined : {}
|
|
108
|
+
responses = { [method === 'delete' ? 204 : 200]: getData() }
|
|
109
|
+
break
|
|
110
|
+
|
|
111
|
+
case '/query':
|
|
112
|
+
summary = `Query all ${instance.collectionName}`
|
|
113
|
+
parameters = queryParams
|
|
114
|
+
responses = { 200: getData(true) }
|
|
115
|
+
break
|
|
116
|
+
|
|
117
|
+
case '/schema':
|
|
118
|
+
summary = `Retrieve ${instance.schemaName} schema`
|
|
119
|
+
break
|
|
120
|
+
}
|
|
121
|
+
r.meta[method] = { summary, parameters, requestBody, responses }
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Clones an object and converts any Dates and ObjectIds to Strings
|
|
128
|
+
* @param {Object} data
|
|
129
|
+
* @returns A clone object with stringified ObjectIds
|
|
130
|
+
*/
|
|
131
|
+
static stringifyValues (data) {
|
|
132
|
+
return Object.entries(data).reduce((cloned, [key, val]) => {
|
|
133
|
+
const type = val?.constructor?.name
|
|
134
|
+
cloned[key] =
|
|
135
|
+
type === 'Date' || type === 'ObjectId'
|
|
136
|
+
? val.toString()
|
|
137
|
+
: type === 'Array' || type === 'Object'
|
|
138
|
+
? this.stringifyValues(val)
|
|
139
|
+
: val
|
|
140
|
+
return cloned
|
|
141
|
+
}, Array.isArray(data) ? [] : {})
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export default AbstractApiUtils
|
package/lib/DataCache.js
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import { App } from 'adapt-authoring-core'
|
|
2
|
-
/**
|
|
3
|
-
* Time-limited data cache
|
|
4
|
-
* @memberof api
|
|
5
|
-
*/
|
|
6
|
-
class DataCache {
|
|
7
|
-
/** @override */
|
|
8
|
-
constructor ({ enable, lifespan }) {
|
|
9
|
-
this.isEnabled = enable !== false
|
|
10
|
-
this.lifespan = lifespan ?? App.instance.config.get('adapt-authoring-api.defaultCacheLifespan')
|
|
11
|
-
this.cache = {}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Retrieve cached data, or run fresh query if no cache exists or cache is invalid
|
|
16
|
-
* @param {Object} query
|
|
17
|
-
* @param Object} options
|
|
18
|
-
* @param {Object} mongoOptions
|
|
19
|
-
* @returns {*} The cached data
|
|
20
|
-
*/
|
|
21
|
-
async get (query, options, mongoOptions) {
|
|
22
|
-
const key = JSON.stringify(query) + JSON.stringify(options) + JSON.stringify(mongoOptions)
|
|
23
|
-
this.prune()
|
|
24
|
-
if (this.cache[key]) {
|
|
25
|
-
return this.cache[key].data
|
|
26
|
-
}
|
|
27
|
-
const mongodb = await App.instance.waitForModule('mongodb')
|
|
28
|
-
const data = await mongodb.find(options.collectionName, query, mongoOptions)
|
|
29
|
-
this.cache[key] = { data, timestamp: Date.now() }
|
|
30
|
-
return data
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Removes invalid cache data
|
|
35
|
-
*/
|
|
36
|
-
prune () {
|
|
37
|
-
Object.keys(this.cache).forEach(k => {
|
|
38
|
-
const cache = this.cache[k]
|
|
39
|
-
if (Date.now() > (cache.timestamp + this.lifespan)) {
|
|
40
|
-
delete this.cache[k]
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export default DataCache
|
|
1
|
+
import { App } from 'adapt-authoring-core'
|
|
2
|
+
/**
|
|
3
|
+
* Time-limited data cache
|
|
4
|
+
* @memberof api
|
|
5
|
+
*/
|
|
6
|
+
class DataCache {
|
|
7
|
+
/** @override */
|
|
8
|
+
constructor ({ enable, lifespan }) {
|
|
9
|
+
this.isEnabled = enable !== false
|
|
10
|
+
this.lifespan = lifespan ?? App.instance.config.get('adapt-authoring-api.defaultCacheLifespan')
|
|
11
|
+
this.cache = {}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Retrieve cached data, or run fresh query if no cache exists or cache is invalid
|
|
16
|
+
* @param {Object} query
|
|
17
|
+
* @param Object} options
|
|
18
|
+
* @param {Object} mongoOptions
|
|
19
|
+
* @returns {*} The cached data
|
|
20
|
+
*/
|
|
21
|
+
async get (query, options, mongoOptions) {
|
|
22
|
+
const key = JSON.stringify(query) + JSON.stringify(options) + JSON.stringify(mongoOptions)
|
|
23
|
+
this.prune()
|
|
24
|
+
if (this.cache[key]) {
|
|
25
|
+
return this.cache[key].data
|
|
26
|
+
}
|
|
27
|
+
const mongodb = await App.instance.waitForModule('mongodb')
|
|
28
|
+
const data = await mongodb.find(options.collectionName, query, mongoOptions)
|
|
29
|
+
this.cache[key] = { data, timestamp: Date.now() }
|
|
30
|
+
return data
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Removes invalid cache data
|
|
35
|
+
*/
|
|
36
|
+
prune () {
|
|
37
|
+
Object.keys(this.cache).forEach(k => {
|
|
38
|
+
const cache = this.cache[k]
|
|
39
|
+
if (Date.now() > (cache.timestamp + this.lifespan)) {
|
|
40
|
+
delete this.cache[k]
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default DataCache
|
package/lib/typedefs.js
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file exists to define the below types for documentation purposes.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* For AbstractApiModule subclasses the Express ClientRequest object is given an extra apiData property which contains useful data related to the incoming request.
|
|
6
|
-
* Extends Route definition with additional API-specific attributes
|
|
7
|
-
* @memberof api
|
|
8
|
-
* @typedef {Object} ApiRequestData
|
|
9
|
-
* @property {Object} config The API route's config data. Set when the route is initialised.
|
|
10
|
-
* @property {String} collectionName The DB collection name
|
|
11
|
-
* @property {Object} data The request body data
|
|
12
|
-
* @property {Object} query The request query data
|
|
13
|
-
* @property {String} schemaName The schema name for data validation
|
|
14
|
-
* @property {Boolean} modifying Whether the request modifies data
|
|
15
|
-
* @see {ApiRoute}
|
|
16
|
-
*/
|
|
17
|
-
/**
|
|
18
|
-
* Extends the existing Route definition with additional API-specific attributes
|
|
19
|
-
* @memberof api
|
|
20
|
-
* @typedef {Route} ApiRoute
|
|
21
|
-
* @extends {Route}
|
|
22
|
-
* @property {Array<string>} modifiers Defines which HTTP methods can modify data (verbs must be lower-case). This only needs do be defined for routes are non standard. By default, it is assumed that 'get' requests are non-modifying, and 'post', 'put', 'patch' and 'delete' are modifying.
|
|
23
|
-
* @example
|
|
24
|
-
* modifiers: ['post']
|
|
25
|
-
* @property {Boolean} validate Whether the request data should be validated
|
|
26
|
-
* @property {Object} permissions Definition of permissions allowed required to access each handler
|
|
27
|
-
* @property {Array<string>} [permissions.post] Permissions scopes required to access this route
|
|
28
|
-
* @property {Array<string>} [permissions.get] Permissions scopes required to access this route
|
|
29
|
-
* @property {Array<string>} [permissions.put] Permissions scopes required to access this route
|
|
30
|
-
* @property {Array<string>} [permissions.delete] Permissions scopes required to access this route
|
|
31
|
-
* @example
|
|
32
|
-
* {
|
|
33
|
-
* route: '/',
|
|
34
|
-
* handlers: { post: postHandler },
|
|
35
|
-
* permissions: { post: ['write:scope'] }
|
|
36
|
-
* modifiers: ['post'],
|
|
37
|
-
* }
|
|
38
|
-
*/
|
|
39
|
-
/**
|
|
40
|
-
* @memberof api
|
|
41
|
-
* @typedef {Object} InsertOptions
|
|
42
|
-
* @property {String} schemaName Name of the schema to validate against
|
|
43
|
-
* @property {String} collectionName DB collection to insert document into
|
|
44
|
-
* @property {String} validate Whether the incoming data should be validated
|
|
45
|
-
* @property {String} invokePostHook Whether the function should invoke the 'post' action hook on success
|
|
46
|
-
*/
|
|
47
|
-
/**
|
|
48
|
-
* @memberof api
|
|
49
|
-
* @typedef {Object} FindOptions
|
|
50
|
-
* @property {String} schemaName Name of the schema to validate against
|
|
51
|
-
* @property {String} collectionName DB collection to insert document into
|
|
52
|
-
*/
|
|
53
|
-
/**
|
|
54
|
-
* @memberof api
|
|
55
|
-
* @typedef {Object} UpdateOptions
|
|
56
|
-
* @property {String} schemaName Name of the schema to validate against
|
|
57
|
-
* @property {String} collectionName DB collection to insert document into
|
|
58
|
-
* @property {Boolean} validate Whether the incoming data should be validated
|
|
59
|
-
* @property {String} invokePostHook Whether the function should invoke the 'post' action hook on success
|
|
60
|
-
* @property {Boolean} rawUpdate Whether the provided data should be considered 'raw' (i.e. not format and apply $set MongoDB keyword)
|
|
61
|
-
*/
|
|
62
|
-
/**
|
|
63
|
-
* @memberof api
|
|
64
|
-
* @typedef {Object} DeleteOptions
|
|
65
|
-
* @property {String} collectionName DB collection to remove document from
|
|
66
|
-
* @property {String} invokePostHook Whether the function should invoke the 'post' action hook on success
|
|
1
|
+
/**
|
|
2
|
+
* This file exists to define the below types for documentation purposes.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* For AbstractApiModule subclasses the Express ClientRequest object is given an extra apiData property which contains useful data related to the incoming request.
|
|
6
|
+
* Extends Route definition with additional API-specific attributes
|
|
7
|
+
* @memberof api
|
|
8
|
+
* @typedef {Object} ApiRequestData
|
|
9
|
+
* @property {Object} config The API route's config data. Set when the route is initialised.
|
|
10
|
+
* @property {String} collectionName The DB collection name
|
|
11
|
+
* @property {Object} data The request body data
|
|
12
|
+
* @property {Object} query The request query data
|
|
13
|
+
* @property {String} schemaName The schema name for data validation
|
|
14
|
+
* @property {Boolean} modifying Whether the request modifies data
|
|
15
|
+
* @see {ApiRoute}
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Extends the existing Route definition with additional API-specific attributes
|
|
19
|
+
* @memberof api
|
|
20
|
+
* @typedef {Route} ApiRoute
|
|
21
|
+
* @extends {Route}
|
|
22
|
+
* @property {Array<string>} modifiers Defines which HTTP methods can modify data (verbs must be lower-case). This only needs do be defined for routes are non standard. By default, it is assumed that 'get' requests are non-modifying, and 'post', 'put', 'patch' and 'delete' are modifying.
|
|
23
|
+
* @example
|
|
24
|
+
* modifiers: ['post']
|
|
25
|
+
* @property {Boolean} validate Whether the request data should be validated
|
|
26
|
+
* @property {Object} permissions Definition of permissions allowed required to access each handler
|
|
27
|
+
* @property {Array<string>} [permissions.post] Permissions scopes required to access this route
|
|
28
|
+
* @property {Array<string>} [permissions.get] Permissions scopes required to access this route
|
|
29
|
+
* @property {Array<string>} [permissions.put] Permissions scopes required to access this route
|
|
30
|
+
* @property {Array<string>} [permissions.delete] Permissions scopes required to access this route
|
|
31
|
+
* @example
|
|
32
|
+
* {
|
|
33
|
+
* route: '/',
|
|
34
|
+
* handlers: { post: postHandler },
|
|
35
|
+
* permissions: { post: ['write:scope'] }
|
|
36
|
+
* modifiers: ['post'],
|
|
37
|
+
* }
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* @memberof api
|
|
41
|
+
* @typedef {Object} InsertOptions
|
|
42
|
+
* @property {String} schemaName Name of the schema to validate against
|
|
43
|
+
* @property {String} collectionName DB collection to insert document into
|
|
44
|
+
* @property {String} validate Whether the incoming data should be validated
|
|
45
|
+
* @property {String} invokePostHook Whether the function should invoke the 'post' action hook on success
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* @memberof api
|
|
49
|
+
* @typedef {Object} FindOptions
|
|
50
|
+
* @property {String} schemaName Name of the schema to validate against
|
|
51
|
+
* @property {String} collectionName DB collection to insert document into
|
|
52
|
+
*/
|
|
53
|
+
/**
|
|
54
|
+
* @memberof api
|
|
55
|
+
* @typedef {Object} UpdateOptions
|
|
56
|
+
* @property {String} schemaName Name of the schema to validate against
|
|
57
|
+
* @property {String} collectionName DB collection to insert document into
|
|
58
|
+
* @property {Boolean} validate Whether the incoming data should be validated
|
|
59
|
+
* @property {String} invokePostHook Whether the function should invoke the 'post' action hook on success
|
|
60
|
+
* @property {Boolean} rawUpdate Whether the provided data should be considered 'raw' (i.e. not format and apply $set MongoDB keyword)
|
|
61
|
+
*/
|
|
62
|
+
/**
|
|
63
|
+
* @memberof api
|
|
64
|
+
* @typedef {Object} DeleteOptions
|
|
65
|
+
* @property {String} collectionName DB collection to remove document from
|
|
66
|
+
* @property {String} invokePostHook Whether the function should invoke the 'post' action hook on success
|
|
67
67
|
*/
|
package/package.json
CHANGED
|
@@ -1,23 +1,58 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "adapt-authoring-api",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "Abstract module for creating APIs",
|
|
5
|
-
"homepage": "https://github.com/adapt-security/adapt-authoring-api",
|
|
6
|
-
"license": "GPL-3.0",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"main": "index.js",
|
|
9
|
-
"repository": "github:adapt-security/adapt-authoring-api",
|
|
10
|
-
"dependencies": {
|
|
11
|
-
"lodash": "^4.17.21"
|
|
12
|
-
},
|
|
13
|
-
"peerDependencies": {
|
|
14
|
-
"adapt-authoring-auth": "github:adapt-security/adapt-authoring-auth",
|
|
15
|
-
"adapt-authoring-core": "github:adapt-security/adapt-authoring-core",
|
|
16
|
-
"adapt-authoring-jsonschema": "github:adapt-security/adapt-authoring-jsonschema",
|
|
17
|
-
"adapt-authoring-mongodb": "github:adapt-security/adapt-authoring-mongodb"
|
|
18
|
-
},
|
|
19
|
-
"devDependencies": {
|
|
20
|
-
"eslint": "^9.14.0",
|
|
21
|
-
"standard": "^17.1.0"
|
|
22
|
-
|
|
23
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "adapt-authoring-api",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Abstract module for creating APIs",
|
|
5
|
+
"homepage": "https://github.com/adapt-security/adapt-authoring-api",
|
|
6
|
+
"license": "GPL-3.0",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "index.js",
|
|
9
|
+
"repository": "github:adapt-security/adapt-authoring-api",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"lodash": "^4.17.21"
|
|
12
|
+
},
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"adapt-authoring-auth": "github:adapt-security/adapt-authoring-auth",
|
|
15
|
+
"adapt-authoring-core": "github:adapt-security/adapt-authoring-core",
|
|
16
|
+
"adapt-authoring-jsonschema": "github:adapt-security/adapt-authoring-jsonschema",
|
|
17
|
+
"adapt-authoring-mongodb": "github:adapt-security/adapt-authoring-mongodb"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"eslint": "^9.14.0",
|
|
21
|
+
"standard": "^17.1.0",
|
|
22
|
+
"@semantic-release/commit-analyzer": "^9.0.2",
|
|
23
|
+
"@semantic-release/git": "^10.0.1",
|
|
24
|
+
"@semantic-release/github": "^8.0.5",
|
|
25
|
+
"@semantic-release/npm": "^9.0.1",
|
|
26
|
+
"@semantic-release/release-notes-generator": "^10.0.3",
|
|
27
|
+
"conventional-changelog-eslint": "^3.0.9",
|
|
28
|
+
"semantic-release": "^21.0.1",
|
|
29
|
+
"semantic-release-replace-plugin": "^1.2.7"
|
|
30
|
+
},
|
|
31
|
+
"release": {
|
|
32
|
+
"plugins": [
|
|
33
|
+
[
|
|
34
|
+
"@semantic-release/commit-analyzer",
|
|
35
|
+
{
|
|
36
|
+
"preset": "eslint"
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
[
|
|
40
|
+
"@semantic-release/release-notes-generator",
|
|
41
|
+
{
|
|
42
|
+
"preset": "eslint"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"@semantic-release/npm",
|
|
46
|
+
"@semantic-release/github",
|
|
47
|
+
[
|
|
48
|
+
"@semantic-release/git",
|
|
49
|
+
{
|
|
50
|
+
"assets": [
|
|
51
|
+
"package.json"
|
|
52
|
+
],
|
|
53
|
+
"message": "Chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
}
|