mongo-rest-router v0.3.1
Mongo REST Router
Creates an Express route that exposes a Mongo collection via a REST API.
Here's the list of api methods exposed by the route:
- GET /api/v1/:collection - List documents. Uses query-to-mongo{https://www.npmjs.com/package/query-to-mongo} to turn query parameters into search criteria.
- GET /api/v1/:collection/:id - Retrieve a document.
- POST /api/v1/:collection - Store a new document or bulk store a list of document. Response includes insertedId or insertedIds respectively.
- PUT /api/v1/:collection/:id - Update a document.
- PATCH /api/v1/:collection/:id - Update parts of a document using JSON Patch or query parameters.
- DELETE /api/v1/:collection/:id - Delete a document. Set's the deleted property, moving it to the archive, unless the noArchive option is set
true
.
The following archive related routes are added unless noArchive is set true
. Deleted documents are put in the archive (marked with a deleted
field), not deleted immediately.
- GET /api/v1/:collection/archive - List archived documents. Uses query-to-mongo{https://www.npmjs.com/package/query-to-mongo} to turn query parameters into search criteria.
- GET /api/v1/:collection/archive/:id - Retrieve an archived documents.
- PATCH /api/v1/:collection/archive/:id - Modify an archived documents. Useful for removing the deletedOn property, restoring the document.
- DELETE /api/v1/:collection/archive/:id - Delete a document permanently.
An example
The following let's you expose a mongo collection members as a REST API.
Ensure the
MONGO_URL
is set as an env var (that's what thewithDb
middleware uses). For example:mongodb://user:pass@localhost:27017/db
.An alternative is to call MongoRestRoute with an options.db defined.
define a schema using JSON Schema syntax:
members.ts
export interface Member { _id: string name: string email: string address?: string phone?: string } export const memberSchema:JSONSchemaType<Member> = { type: 'object', properties: { _id: {type: 'string'}, name: {type: 'string'}, email: {type: 'string', format: 'email'}, address: {type: 'string', nullable: true}, phone: {type: 'string', nullable: true}, }, required: ['_id', 'name', 'email'], additionalProperties: false, }
Add the route to the express app
routes.ts
import express from 'express' import { MongoRestRoute, withDb } from 'mongo-rest-router' import { membersSchema } from './members.ts' const app = express() app.use('/api/v1/members', withDb, MongoRestRouter('members', membersSchema)) const port = 3000 app.listen(port, () => { console.info(`Example app listening on port ${port}`) })
API
MongoRestRouter
Parameters
- collection
string
name of collection - schema
JSONSchemaType
a JSON Schema definition - options.db
mongodb.Db
(Optional) Mongo database, a function to return one, or a mongo connection string. Usesprocess.env.MONGO_URL
if unset. - options.methods
string[]
(Optional) List of methods to provide. List can include any of:'GET'
,'POST'
,'PUT'
,'PATCH'
, and'DELETE'
. Provides all if unset. - options.noGetSearch
boolean
(Optional) Do not provide the GET / route for searching. - options.noPostBulk
boolean
(Optional) Do not allow an array to be provided to the POST method. - options.resultsField
string
(Optional) Use this instead of the collection name as the search result field. - options.noArchive
boolean
(Optional) Don't set the deletedOn property upon DELETE, remove it immediately. - options.dateFields.createdOn
string
(Optional) Use this instead of 'createdOn' for tracking the POST operations. - options.dateFields.modifiedOn
string
(Optional) Use this instead of 'modifiedOn' for tracking PUT and PATCH operations. - options.dateFields.deletedOn
string
(Optional) Use this instead of 'deletedOn' for tracking DELETE operations.
Returns
- an
express.Router
that exposes the collection via a REST API.
Additional APIs
The following functions may be useful when implementing your own business logic around create or update operations (POST, PUT, PATCH).
applyPatchRequest
A method that applies a PATCH request to an object. The request can be ether a JSON Patch payload or query parameters.
Will throw a ValidationError if the payload is not a JSON Patch.
Example
router.patch(`/api/v1/example`, (req:Request, res:Response)=>{
const origObject = { /* ... get the original object */ }
try {
const patched = applyPatchRequest(origObject, req)
// ... do something with the patched object ... maybe validate it?
} catch (e) {
handleValidationError(e, res)
}
})
getValidate
Returns two functions, validate
and validateBulk
.
Parameters
schema
The JSON Schema to validate payloads againstoptions.dateFields.added
(Optional) Use this field instead ofadded
to record when the document was added to the collection.options.dateFields.lastModified
Use this field instead oflastModified
to record when the document was last modified.options.dateFields.deleted
Use this field instead ofdeleted
to record when the document was archived.
Returns
Two functions, validate which will return a typed object or throw a ValidationError, and validateBulk that will validate either a single object or an array of objects.
function validate<T>(payload:unknown, allowMangedDates:boolean):T
function validateBulk<T>(payload:unknown, allowManagedDates):T|T[]
The allowManagedDates function will add the dateFields to the document in order to validate update payloads where those field might exist (PUT and PATCH).
handleValidationError
Sends a 400 Bad Request response when a SyntaxError (likely due to invalid JSON) or a ValidationError is thrown. Returns a payload with an error
field and either
jsonParseError
or validationErrors
with the details.
Rethrows the error if it is not either of those.
Parameters
error
The caught errorres
The response object
Example
router.post('/api/v1/my-collection', json(), (req:Request, res:Response) => {
const { validateBulk } = getValidate(myJSONSchema)
try {
validateBulk(req.body)
// ... do something with the body
} catch (e) {
handleValidationError(e, res)
}
})
withDb
A middleware function that attaches a Mongo database instance (mongodb.Db
) to the request
at req.locals.db
. The database connection is defined by the env var MONGO_URL
.
Parameters
db
(Optional) A string (ie., a mongoDb url), a mongodb.Db, or a function that returns a Db. If db is undefined theMONGO_URL
env var will be used.
Returns
An express middleware that sets req.locals.db
.
ValidationError
An error thrown when the object does not conform to the schema.
Fields
errors
A list of ErrorObjectsinterface ErrorObject { keyword: string // validation keyword. instancePath: string // JSON Pointer to the location in the data instance (e.g., `"/prop/1/subProp"`). schemaPath: string // JSON Pointer to the location of the failing keyword in the schema params: object // type is defined by keyword value, see below // params property is the object with the additional information about error // it can be used to generate error messages // (e.g., using [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) package). // See below for parameters set by all keywords. propertyName?: string // set for errors in `propertyNames` keyword schema. // `instancePath` still points to the object in this case. message?: string // the error message (can be excluded with option `messages: false`). // Options below are added with `verbose` option: schema?: any // the value of the failing keyword in the schema. parentSchema?: object // the schema containing the keyword. data?: any // the data validated by the keyword. }
TODO
- Add business logic callbacks as options