lengoo-api-response-formatter
Advanced tools
Comparing version
@@ -53,5 +53,7 @@ const _ = require('lodash'); | ||
constructor() { | ||
this._status = 200; | ||
this._data = []; | ||
this._error = {}; | ||
this._validations = []; | ||
this._mongoError = {}; | ||
} | ||
@@ -61,2 +63,22 @@ | ||
* | ||
* @returns int | ||
*/ | ||
get status() { | ||
return this._status; | ||
} | ||
/** | ||
* | ||
* @param input int | ||
*/ | ||
set status(input) { | ||
if (Number.isInteger(input)) { | ||
throw new TypeError('"status" must to be an integer, ' + (typeof input) + ' given.'); | ||
} | ||
this._status = input | ||
} | ||
/** | ||
* | ||
* @param input (Object|Array) | ||
@@ -66,5 +88,14 @@ */ | ||
if (input instanceof Object === false && input instanceof Array === false) { | ||
throw new TypeError('"data" must be instance of Object or Array.'); | ||
throw new TypeError('"data" must to be an instance of Object or Array, ' + (typeof input) + ' given.'); | ||
} else if (input instanceof Array) { | ||
// Remove version tag | ||
for (let i in input) { | ||
input[i]['__v'] = undefined; | ||
} | ||
} else if (input instanceof Object) { | ||
// Remove version tag | ||
input.__v = undefined; | ||
} | ||
this._status = Response.CODES.SUCCESS; | ||
this._data = input; | ||
@@ -78,2 +109,6 @@ } | ||
set error(input) { | ||
if (input instanceof Object === false) { | ||
throw new TypeError('"error" must to an instance of Object, ' + (typeof input) + ' given.'); | ||
} | ||
let defaults = { | ||
@@ -90,6 +125,24 @@ code: '', | ||
_.forOwn(Response.ERRORS, (value, key) => { | ||
if (value.code === input.code && value.message === input.message) { | ||
if (_.has(Response.CODES, key)) { | ||
this._status = Response.CODES[key]; | ||
} | ||
return false; | ||
} | ||
}); | ||
this._error = {...defaults, ...error}; | ||
} | ||
/** | ||
* Add a single validation error | ||
* | ||
* @param input Object | ||
*/ | ||
addValidation(input) { | ||
if (input instanceof Object === false) { | ||
throw new TypeError('Validation items must be objects, ' + (typeof input) + ' given'); | ||
} | ||
this._validations.push(this._formatValidation(input)); | ||
@@ -103,3 +156,3 @@ this._checkValidationError(); | ||
*/ | ||
set validation(input) { | ||
set validations(input) { | ||
let validations = []; | ||
@@ -112,2 +165,6 @@ | ||
for (let obj of input) { | ||
if (obj instanceof Object === false) { | ||
throw new Error('The "validation" items must to be an instance of Object, ' + (typeof obj) + ' given'); | ||
} | ||
validations.push(this._formatValidation(obj)); | ||
@@ -154,2 +211,55 @@ } | ||
/** | ||
* Format the response according to the given mongodb error | ||
* | ||
* @param err Object | ||
*/ | ||
set mongoError(err) { | ||
this._mongoError = err; | ||
let validations = []; | ||
if (_.has(err, 'errors')) { | ||
_.forOwn(err.errors, (value, key) => { | ||
let validation = { | ||
message: value.message, | ||
attribute: value.properties.path, | ||
value: (value.properties.value === undefined) | ||
? 'undefined' | ||
: value.properties.value | ||
}; | ||
switch (value) { | ||
case 'ValidatorError': | ||
this._status = Response.CODES.UNPROCESSABLE_ENTITY; | ||
validation = { | ||
code: 'property-validation', | ||
...validation | ||
}; | ||
validations.push(this._formatValidation(validation)); | ||
break; | ||
} | ||
}); | ||
} else if (err.name === 'CastError') { | ||
switch (err.kind) { | ||
case 'ObjectId': | ||
this._status = Response.CODES.BAD_REQUEST; | ||
let validation = { | ||
code: 'incorrect-id-format', | ||
message: err.message, | ||
attribute: err.path, | ||
value: (err.value === undefined) | ||
? 'undefined' | ||
: err.value | ||
}; | ||
validations.push(this._formatValidation(validation)); | ||
break; | ||
} | ||
} | ||
this._validations = [...this._validations, ...validations]; | ||
this._checkValidationError(); | ||
} | ||
/** | ||
* Get the formatted response | ||
@@ -156,0 +266,0 @@ * |
{ | ||
"name": "lengoo-api-response-formatter", | ||
"version": "1.0.3", | ||
"version": "1.1.0", | ||
"description": "A lib to keep your responses formatted and consistent through your project", | ||
@@ -15,3 +15,5 @@ "main": "./lib/Response.js", | ||
"api", | ||
"response" | ||
"response", | ||
"node", | ||
"express" | ||
], | ||
@@ -18,0 +20,0 @@ "author": "Rodrigo Duarte <rodrigo.duarte@lengoo.de> (https://www.lengoo.de)", |
240
README.md
@@ -10,2 +10,4 @@ # Lengoo API Response Formatter | ||
- Predefined error messages | ||
- HTTP status guessing | ||
- Mongo errors treatment | ||
- Response formatter | ||
@@ -55,21 +57,17 @@ | ||
module.exports.getById = (req, res) => { | ||
let employee = _.find(employees, { _id: req.swagger.params.id.value }); | ||
module.exports.get = (req, res) => { | ||
let response = new Response(); | ||
if (employee === undefined) { | ||
response.error = Response.ERRORS.NOT_FOUND; | ||
// You can also especify your own error | ||
// response.error = { | ||
// code: 'not-found', | ||
// message: 'There is no employee to the given ID' | ||
// } | ||
Model.findOne({_id: req.swagger.params.id.value}, (err, doc) => { | ||
if (err) { | ||
response.mongoError = err; | ||
} else if (company === null) { | ||
response.error = Response.ERRORS.NOT_FOUND; | ||
} else { | ||
response.data = doc; | ||
} | ||
res.status(Response.CODES.NOT_FOUND); | ||
res.status(response.status); | ||
res.json(response.get()); | ||
} else { | ||
response.data = employee; | ||
res.json(response.get()); | ||
} | ||
}); | ||
}; | ||
@@ -112,5 +110,215 @@ | ||
If you didn't specify an error, the default error for validations will be added to the response. | ||
If you do not specify an error, the default error for validations will be added to the response. | ||
## API | ||
### .status | ||
*Default: 200* | ||
#### set | ||
Define the HTTP response code. | ||
##### Accepted types: | ||
- integer | ||
##### Examples: | ||
let response = new Response(); | ||
response.status = Response.CODES.BAD_REQUEST; | ||
// Or | ||
// response.status = 400; | ||
#### get | ||
Get the HTTP response code. | ||
##### Example: | ||
let response = new Response(); | ||
response.status = Response.CODES.BAD_REQUEST; | ||
console.log(response.status); | ||
--- | ||
### .data | ||
#### set | ||
Set the data to be returned on `data` response property. | ||
*Note: The `200` status code will be added to the response.* | ||
##### Accepted types: | ||
- Array | ||
- Object | ||
##### Example: | ||
let response = new Response(); | ||
response.data = [{ | ||
_id: 5ad60b78779c4e0ec54aa0d7, | ||
name: 'Lengoo' | ||
}]; | ||
--- | ||
### .error | ||
#### set | ||
Set the error to be returned on `error` response property. | ||
*Important: If the given value is one of the predefined error messages, the library will try to set the response `status`.* | ||
##### Accepted types: | ||
- Object | ||
##### Examples: | ||
Custom error: | ||
let response = new Response(); | ||
response.error = [{ | ||
code: 'some-custom-code', | ||
message: 'Something went wrong.' | ||
}]; | ||
Predefined error: | ||
let response = new Response(); | ||
response.status = Response.CODES.BAD_REQUEST; | ||
### .mongoError | ||
#### set | ||
Set the mongo error to be treated by the library. | ||
The library will try to identify the error type, set the correct HTTP status and construct the appropriated response data; | ||
##### Accepted types: | ||
- Object (Mongo Error) | ||
##### Example: | ||
let response = new Response(); | ||
Model.find({}, (err, doc) => { | ||
if (err) { | ||
response.mongoError = err; | ||
} else { | ||
response.data = doc; | ||
} | ||
res.status(response.status); | ||
res.json(response.get()); | ||
}); | ||
### .validations | ||
#### set | ||
Set a collection of validation errors to be returned on `validations` response property. | ||
##### Accepted types: | ||
- Array | ||
*Important: the items of the given array must to be objects.* | ||
##### Example: | ||
let response = new Response(); | ||
response.validations = [ | ||
{ | ||
code: "some-validation-code", | ||
message: Human message"', | ||
attribute: "attribute-that-caused-the-error", | ||
value: "given-value-for-attribute" | ||
}, | ||
{ | ||
code: "another-validation-code", | ||
message: Human message"', | ||
attribute: "attribute-that-caused-the-error", | ||
value: "given-value-for-attribute" | ||
} | ||
]; | ||
### .addValidation() | ||
Append a single validation error to the validations collection. | ||
##### Accepted types: | ||
- Object | ||
##### Example: | ||
let response = new Response(); | ||
response.addValidation({ | ||
code: "another-validation-code", | ||
message: Human message"', | ||
attribute: "attribute-that-caused-the-error", | ||
value: "given-value-for-attribute" | ||
}); | ||
### .get() | ||
Retrieve the formatted response. | ||
##### Example: | ||
let response = new Response(); | ||
response.error = Response.ERRORS.BAD_REQUEST; | ||
res.json(response.get()); | ||
## Static | ||
### HTTP Codes | ||
##### Values: | ||
SUCCESS: 200, | ||
CREATED: 201, | ||
ACCEPTED: 202, | ||
NO_CONTENT: 204, | ||
BAD_REQUEST: 400, | ||
MOVED_PERMANENTLY: 301, | ||
FOUND: 302, | ||
SEE_OTHER: 303, | ||
UNAUTHORIZED: 401, | ||
FORBIDDEN: 403, | ||
NOT_FOUND: 404, | ||
CONFLICT: 409, | ||
UNPROCESSABLE_ENTITY: 422, | ||
NOT_IMPLEMENTED: 501 | ||
##### Example | ||
let response = new Response(); | ||
response.status = Response.CODES.NOT_FOUND; | ||
### Error messages | ||
##### Values: | ||
BAD_REQUEST: { | ||
code: 'bad-request', | ||
message: 'The given data could not been processed' | ||
}, | ||
UNAUTHORIZED: { | ||
code: 'unauthorized', | ||
message: 'Authentication failed or was not provided' | ||
}, | ||
FORBIDDEN: { | ||
code: 'forbidden', | ||
message: 'You don\'t have the required permissions to complete this operation' | ||
}, | ||
NOT_FOUND: { | ||
code: 'not-found', | ||
message: 'The requested object was not found' | ||
}, | ||
CONFLICT: { | ||
code: 'conflict', | ||
message: 'The request was not processed due to a conflict' | ||
}, | ||
UNPROCESSABLE_ENTITY: { | ||
code: 'validation-error', | ||
message: 'The request was not processed due to validation issues' | ||
} | ||
##### Example | ||
let response = new Response(); | ||
response.error = Response.ERRORS.UNPROCESSED_ENTITY; | ||
## Tests | ||
Coming soon |
16164
93.84%237
69.29%321
184.07%