A object mapper for use in my personal projects. With this project you can create a new object using a source object and a model specification.
const model = {
id: { type: 'direct' },
name: { type: 'direct', from: 'firstName' },
amt: { type: 'number', from: 'amount' }
}
const sourceObject = {
id: 7,
firstName: 'John',
amount: 123.75
}
const destObject = await map(sourceObject, model);
//or
map(sourceObject, model).then(result => {
const destObject = result;
}).catch(err => {
throw err
});destObject will be an object like this:
{ id: 7, name: 'John', amt: 123.75 }A model is defined with one key for each map you need to have in the final destination object.
For each key you have to define a type key with one of the following values: "direct", "number", "date" or "custom".
Use this type to extract a value directly from the a key of the sourceObject. If you specify a from key, the value will be retrieved from the key you specify as a value for the from key. Otherwise the value the value will be retrieved from the same name of the key you are defining.
see the keys name and id from the sample above.
The value will be converted to string using the
.toStringjavascript method.
Use this type to extract a value and convert it to a number. You can specify a from key if you want to use a source key different to the key being defined.
This type of map uses javascript's parseFloat function to convert the value. It will throw a ModelMapperFieldError in case of a failed conversion to a number.
Use this type to extract a value and convert it to a Date. You can specify a from key if you want to use a source key different from the key being defined.
This type of map uses javascript's new Date() constructor to convert the value. It will throw a ModelMapperFieldError in case of a failed conversion to a Date.
Use this type to extract a value using a custom function or object provided in the required map key. If you provide an object it will be returned as is.
In case you provide a function to the map key, the mapper will call with it with three arguments:
sourceObject: to pass to the function the sourceObject.key: the key triggering the map function.mapModelSpec: the full map specification for the key triggering the function. You can use custom keys in this definition if you are going to need these custom keys in your map function.
required: used to ensure the value is not undefined or null or empty string. Applies to all types.min: used to restrict the value to this minimum value. Applies tonumberanddate.max: used to restrict the value to this maximum value. Applies tonumberanddate.minLength: used to restrict the final value to a minimumLength. Applies todirectandcustom.maxLength: used to restrict the final value to a maximumLength. Applies todirectandcustom.regExp: used to check the final value towards a javascript'sRegExp.test. Applies todirectandcustom.
All of the keys that apply to
type = 'custom'will be checked after the evaluation of themapfunction or object.
const model = {
id: { type: 'direct' },
name: { type: 'direct', from: 'firstName' },
//amt is restricted to a minimum value of 100
amt: { type: 'number', from: 'amount', min: 100 },
//birth date is restricted to a minimum value of January 1st, 1900
birthDate: { type: 'date', min: new Date('1900/01/01') }
}
const sourceObject = {
id: 7,
firstName: 'John',
amount: 123.75,
birthDate: '1800/03/01'
}
//Will throw because the provided BirthDate is older than January 1st, 1900
try {
const destObject = await map(sourceObject, model);
} catch (err) {
const errors = Object.keys(err.results)
.filter(key => err.results[key].error)
.map(errorKey => err.results[errorKey]);
//errors array will contain all keys with their error message.
}This library provides Middlewares for mapping from a request and to a response.
const { mapBodyMiddleware } = request('@josesjs/model-mapper');
const model = {
id: { type: 'direct' },
name: { type: 'direct', from: 'firstName' },
//amt is restricted to a minimum value of 100
amt: { type: 'number', from: 'amount', min: 100 },
//birth date is restricted to a minimum value of January 1st, 1900
birthDate: { type: 'date', min: new Date('1900/01/01') }
}
expressApp.use('/endpoint', mapBodyMiddleware(model), (req, res) => {
res.status(200).json(req.mappedBody);
});When you provide this middleware in the endpoint, the req.body object will be used as a sourceObject to be mapped using the model provided. If no errors, the mapped model will be available in the req.mappedBody variable for the following middlewares.
if there is no subsequents middlewares provided, mapBodyMiddleware will throw an error with the message
'mapBodyMiddleware expect a next function to be defined.'.
const { mapResponseMiddleware } = require('@josesjs/model-mapper');
//expected a model to map the mappedBody
expressApp.use('/endpoint', mapBodyMiddleware(...), mapResponseMiddleware(
model
));When you provide this middleware to an endpoint. the req.mappedBody variable will be mapped with the model variable and returned to the response as a JSON with an status code = 200;
If you want to override the status code you can pass your customized number to the second parameter of this function. Also if you want to override the req.mappedBody with another variable you can provide a key as a third parameter. The function will look for this key first in the response, if not found there, in the request, if not found there will use the req.mappedBody.
You can use this middleware to catch the errors thrown by the map function. It has a unique optional parameter to use if you want to override the default mapping for errors.
I'm providing some functions to help setup routes in express.js
setupControllerServiceMiddleware(inModel, outModel, serviceCallback, defaultStatusCode = 200)
Use this function to generate an express Middleware that maps the request.body using the inModel argument, following by a call to the serviceCallback method. This method will be called with the arguments (model, req, res). The return value of the serviceCallback will be mapped using the outModel argument and returned to the http client with an status code provided in the optional defaultStatusCode parameter.
In case of errors, this middleware will call the next(err) express function.
setupControllerMiddleware(inModel, outModel, middleware, defaultStatusCode = 200)
Use this function to generate an express Middleware that maps the request.body using the inModel argument. After the req.body is mapped, the middleware provided in the middleware argument will be called.
This middleware will have access to the mapped object in the req.mappedBody variable. You can do any logic you need to made in order to process the request.
After the request process, you can end the request inside of the middleware or set the variable res.mappedBody to the result you want to map using the outModel model. For this you have to call next() inside of your customized middleware.
If you call next with an
Errorinstance as argument, the first express.js error handler middleware will be called skipping any following non-error handlers middlewares.