Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
* @namespace api
*/
export { default as AbstractApiModule } from './lib/AbstractApiModule.js'
export { default as AbstractApiUtils } from './lib/AbstractApiUtils.js'
export { default } from './lib/AbstractApiModule.js'
/** @deprecated Use named import { stringifyValues } from 'adapt-authoring-core' instead */
export { stringifyValues } from 'adapt-authoring-core'
19 changes: 13 additions & 6 deletions lib/AbstractApiModule.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import _ from 'lodash'
import { AbstractModule, Hook } from 'adapt-authoring-core'
import ApiUtils from './AbstractApiUtils.js'
import { AbstractModule, Hook, stringifyValues } from 'adapt-authoring-core'
import { argsFromReq, generateApiMetadata, httpMethodToDBFunction } from './utils.js'
import DataCache from './DataCache.js'
/**
* Abstract module for creating APIs
Expand Down Expand Up @@ -177,7 +177,14 @@ class AbstractApiModule extends AbstractModule {
return this.log('error', 'Must set API root before calling useDefaultConfig function')
}
/** @ignore */ this.routes = this.DEFAULT_ROUTES
ApiUtils.generateApiMetadata(this)
this.generateApiMetadata()
}

/**
* Generates REST API metadata and stores on route config
*/
generateApiMetadata () {
generateApiMetadata(this)
}

/**
Expand Down Expand Up @@ -349,7 +356,7 @@ class AbstractApiModule extends AbstractModule {
requestHandler () {
const requestHandler = async (req, res, next) => {
const method = req.method.toLowerCase()
const func = this[ApiUtils.httpMethodToDBFunction(method)]
const func = this[httpMethodToDBFunction(method)]
if (!func) {
return next(this.app.errors.HTTP_METHOD_NOT_SUPPORTED.setData({ method }))
}
Expand All @@ -361,7 +368,7 @@ class AbstractApiModule extends AbstractModule {
if (preCheck) {
await this.checkAccess(req, req.apiData.query)
}
data = await func.apply(this, ApiUtils.argsFromReq(req))
data = await func.apply(this, argsFromReq(req))
if (postCheck) {
data = await this.checkAccess(req, data)
}
Expand Down Expand Up @@ -654,7 +661,7 @@ class AbstractApiModule extends AbstractModule {

if (options.invokePreHook !== false) await this.preUpdateHook.invoke(originalDoc, formattedData.$set, options, mongoOptions)
formattedData.$set = await this.validate(options.schemaName, {
...ApiUtils.stringifyValues(originalDoc),
...stringifyValues(originalDoc),
...formattedData.$set
}, options)

Expand Down
145 changes: 0 additions & 145 deletions lib/AbstractApiUtils.js

This file was deleted.

4 changes: 4 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { argsFromReq } from './utils/argsFromReq.js'
export { generateApiMetadata } from './utils/generateApiMetadata.js'
export { httpMethodToAction } from './utils/httpMethodToAction.js'
export { httpMethodToDBFunction } from './utils/httpMethodToDBFunction.js'
17 changes: 17 additions & 0 deletions lib/utils/argsFromReq.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Generates a list of arguments to be passed to the MongoDBModule from a request object
* @param {external:ExpressRequest} req
* @return {Array<*>}
* @memberof api
*/
export function argsFromReq (req) {
const opts = { schemaName: req.apiData.schemaName, collectionName: req.apiData.collectionName }
switch (req.method) {
case 'GET': case 'DELETE':
return [req.apiData.query, opts]
case 'POST':
return [req.apiData.data, opts]
case 'PUT': case 'PATCH':
return [req.apiData.query, req.apiData.data, opts]
}
}
69 changes: 69 additions & 0 deletions lib/utils/generateApiMetadata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* Generates REST API metadata and stores on route config
* @param {AbstractApiModule} instance The current AbstractApiModule instance
* @memberof api
*/
export function generateApiMetadata (instance) {
const getData = isList => {
const $ref = { $ref: `#/components/schemas/${instance.schemaName}` }
return {
description: `The ${instance.schemaName} data`,
content: { 'application/json': { schema: isList ? { type: 'array', items: $ref } : $ref } }
}
}
const queryParams = [
{
name: 'limit',
in: 'query',
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')})`
},
{
name: 'page',
in: 'query',
description: 'The page of results to return (determined from the limit value)'
}
]
const verbMap = {
put: 'Replace',
get: 'Retrieve',
patch: 'Update',
delete: 'Delete',
post: 'Insert'
}
instance.routes.forEach(r => {
r.meta = {}
Object.keys(r.handlers).forEach(method => {
let summary, parameters, requestBody, responses
switch (r.route) {
case '/':
if (method === 'post') {
summary = `${verbMap.post} a new ${instance.schemaName} document`
requestBody = getData()
responses = { 201: getData() }
} else {
summary = `${verbMap.get} all ${instance.collectionName} documents`
parameters = queryParams
responses = { 200: getData(true) }
}
break

case '/:_id':
summary = `${verbMap[method]} an existing ${instance.schemaName} document`
requestBody = method === 'put' || method === 'patch' ? getData() : method === 'delete' ? undefined : {}
responses = { [method === 'delete' ? 204 : 200]: getData() }
break

case '/query':
summary = `Query all ${instance.collectionName}`
parameters = queryParams
responses = { 200: getData(true) }
break

case '/schema':
summary = `Retrieve ${instance.schemaName} schema`
break
}
r.meta[method] = { summary, parameters, requestBody, responses }
})
})
}
19 changes: 19 additions & 0 deletions lib/utils/httpMethodToAction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Converts HTTP methods to a corresponding 'action' for use in auth
* @param {String} method The HTTP method
* @return {String}
* @memberof api
*/
export function httpMethodToAction (method) {
switch (method.toLowerCase()) {
case 'get':
return 'read'
case 'post':
case 'put':
case 'patch':
case 'delete':
return 'write'
default:
return ''
}
}
15 changes: 15 additions & 0 deletions lib/utils/httpMethodToDBFunction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Converts HTTP methods to a corresponding database function
* @param {String} method The HTTP method
* @return {String}
* @memberof api
*/
export function httpMethodToDBFunction (method) {
switch (method.toLowerCase()) {
case 'post': return 'insert'
case 'get': return 'find'
case 'put': case 'patch': return 'update'
case 'delete': return 'delete'
default: return ''
}
}
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"test": "node --test 'tests/**/*.spec.js'"
},
"dependencies": {
"adapt-authoring-core": "^1.7.0",
"adapt-authoring-core": "^2.0.0",
"lodash": "^4.17.21"
},
"peerDependencies": {
Expand Down
Loading
Loading