This section describes general use tools that can solve common needs of Node.js applications.
Creates a Bunyan logger, which works with log levels and has a really flexible logging style.
This function takes an options object which accepts the properties described in the table below.
Property | Type | Required | Description | Default value |
---|---|---|---|---|
name |
string | No | The name of the application. | app log name |
logLevels |
string array | No | The log levels that will be sent to the output. Messages logged in other levels will be ignored. The levels are fatal , error , warn , info , debug and trace. |
[fatal , error , warn , info ] |
logOutput |
string | No | The log output type. For using the standard output, specify standard-streams . For saving logs in a file system folder, specify rotating-file . |
standard-streams |
logDirectory |
string | No | The directory in which logs files must be stored (relative to the application start directory). This parameter is only used if the selected log output is rotating-file . |
./logs |
const tools = require('itaas-nodejs-tools');
let logger = tools.createLogger({
name: 'your-app',
logLevels: ['fatal', 'error', 'warn'],
logOutput: 'rotating-file',
logDirectory: './logs'
});
logger.error('A terrible error has occurred!'); // logged in "./logs"
logger.info('Doing everyday things'); // not logged because info level is not enabled
Creates an empty service locator.
A service locator is a collection of keys and values with the specific purpose of acting as a dependency injection tool.
Constructing an application in a layer-based structure lets you easily replace layers (depending on business rules, or for test purposes), and the service locator helps with that by keeping references to layer implementations.
const tools = require('itaas-nodejs-tools');
class UserService {
getUser(id) {
// complicated requests and database queries
return user;
}
}
class MockUserService{
getUser(id){
let user = fakeUsersInMemory[id];
return user;
}
}
let serviceLocator = tools.createServiceLocator();
// for application setup
serviceLocator.addService('user-service', new UserService());
// for unit test setup
serviceLocator.addService('user-service', new MockUserService());
// for either of the above, the code that uses the service is the same
let userService = serviceLocator.getService('user-service');
userService.getUser(id);
Creates a call context with configuration, logger and service locator for a single request or execution.
Call context is one of the most important concepts of iTaaS components. It concentrates generally useful things in a single object, which should be passed around as a parameter throughout the execution.
Parameter | Type | Required | Description | Default value |
---|---|---|---|---|
callId |
string | Yes | A unique ID for the request/execution. It is useful to identify the request/execution in logs. | - |
config |
object | Yes | An object containing all settings your application needs. | - |
logger |
object | Yes | A logger for the request/execution. See createLogger. | - |
serviceLocator |
object | Yes | A service locator for the request/execution. See createServiceLocator. | - |
const tools = require('itaas-nodejs-tools');
const uuid = require('uuid').v4;
let callId = uuid();
let config = { key: "value" };
let logger = tools.createLogger();
let serviceLocator = tools.createServiceLocator();
let context = tools.createCallContext(callId, config, logger, serviceLocator);
Using a call context
function anyFunction(context /* , otherParameters, ... */) {
console.log(context.callId); // some UUID
console.log(context.config.key); // "value"
context.logger.info('Now I can log anywhere in the code!');
context.serviceLocator.getService('service-accessible-anywhere');
otherFunction(context /* , otherParameters, ... */);
}
Creates a field selector, a tool that selects properties recursively in a Javascript object, creating a new object with only the selected properties.
The only parameter is a string description of the properties which must be selected, with a specific syntax. The created selector has a function select
, whose single parameter is the source object to select properties from.
Notes
- Properties are case-insensitive and must be separated by comma (
,
) - Nested properties can be selected by joining the property names with dots (
.
) - Properties or nested properties that don't exist will never cause an error
- Selections on arrays are done for each of their elements.
const tools = require('itaas-nodejs-tools');
let source = {
name: 'Don Vito Corleone',
age: 53,
address: {
country: 'United States',
city: 'New York',
street: { name: 'Mott Street', postalCode: '10012' }
},
actors: [
{ name: 'Robert De Niro', startAge: 25, endAge: 31 },
{ name: 'Marlon Brando', startAge: 53, endAge: 63 }
]
};
let selector = tools.createFieldSelector('address.city,address.street.postalCode,potato,actors.name');
let selection = selector.select(source);
console.log(selection);
/* {
address: {
city: 'New York'
street: { postalCode: '10012' }
},
actors: [
{ name: 'Robert De Niro' },
{ name: 'Marlon Brando' }
]
} */
The field selector is particularly useful for letting application clients choose which fields of the resource they want returned. A query string parameter can be exposed for that purpose.
GET /users/1234?fields=name
{
"name": "Michael Jackson"
}
GET /users/1234?fields=name,job
{
"name": "Michael Jackson",
"job": "musician"
}
Creates a remote config loader that provides a config object obtained from a JSON in the given URL. It caches the config for a period of time that can be specified, then refreshes it after that time has elapsed since the last refresh.
const tools = require('itaas-nodejs-tools');
let configUrl = 'http://config.com/my-config.json';
let refreshTimeSeconds = 60;
let configLoader = tools.createRemoteConfig(configUrl, refreshTimeSeconds);
configLoader.getConfigObject(context)
.then((config) => {
console.log('My config: ' + JSON.stringify(config));
});
This function accepts these parameters:
Parameter | Type | Required | Description | Default value |
---|---|---|---|---|
url |
string | Yes | The URL where the config is located | - |
refreshTimeSeconds |
integer | No | The amount of seconds before the config cache is considered to be expired and a refresh is needed. If not specified, the config will only be retrieved once and will never be refreshed. | no refresh |
The config loader has a function getConfigObject
that only receives a context. It returns the config from the cache, but first refreshes the cache if the refresh time has elapsed.
Creates a remote object loader that provides a object obtained from a JSON in the given URL. It caches the config for a period of time that can be specified, then refreshes it after that time has elapsed since the last refresh the object asynchronous.
const tools = require('itaas-nodejs-tools');
let objectUrl = 'http://config.com/my-config.json';
let refreshTimeSeconds = 60;
let objectLoader = tools.cacheRemoteObject(objectUrl, refreshTimeSeconds);
objectLoader.getFresh(context)
.then((remoteObject) => {
console.log('My config: ' + JSON.stringify(remoteObject));
});
This function accepts these parameters:
Parameter | Type | Required | Description | Default value |
---|---|---|---|---|
url |
string | Yes | The URL where the object is located | - |
refreshTimeSeconds |
integer | No | The amount of seconds before the object cache is considered to be expired and a refresh is needed. If not specified, the config will only be retrieved once and will never be refreshed. | no refresh |
The Cache Object Remote has a function getFresh
that only receives a context. It returns a freshy object, and update the cache status, another function is getCached
, that will return the cached object and check if a refresh is needed (if needed, runs the refreshCache
assyncronous).
The time services from iTaaS Node.js Tools are objects with a getNow
parameterless function which returns a Javascript Date object.
You can easily replace a time service using a service locator.
You can implement your own time services, but iTaaS Node.js Tools provides two simple ones for convenience.
Creates a time service which always responds the specified date. It is useful for testing applications with time-related rules, such as token expiration, resource expiration, date filters, etc.
const tools = require('itaas-nodejs-tools');
let fixedTimeService = tools.createFixedTimeService(new Date('2016-06-27T04:54:32Z'));
let now = fixedTimeService.getNow();
console.log(now.toISOString());
// "2016-06-27T04:54:32Z"
Creates a time service which responds the current date.
const tools = require('itaas-nodejs-tools');
let currentTimeService = tools.createCurrentTimeService();
let now = currentTimeService.getNow();
console.log(now.toISOString());
// <current date in ISO-8601 format>
Under number
, there are some handy functions for interpreting numbers, which sometimes reach the application as strings.
Returns true
if the parameter is a 32-bit integer or a string that can be parsed into a 32-bit integer, false
otherwise.
const tools = require('itaas-nodejs-tools');
console.log(tools.number.isInt32(-2147483648)); // true
console.log(tools.number.isInt32('10')); // true
console.log(tools.number.isInt32('eleven')); // false
console.log(tools.number.isInt32(1.2)); // false
Returns the integer value of the parameter if it's acceptable by isInt32
, throws an Error
otherwise.
const tools = require('itaas-nodejs-tools');
console.log(tools.number.parseInt32('10')); // 10
tools.number.parseInt32('eleven'); // Error!
Returns true
if the parameter is a single-precision floating point number or a string that can be parsed into a single-precision floating point number, false
otherwise.
const tools = require('itaas-nodejs-tools');
console.log(tools.number.isFloat('10')); // true
console.log(tools.number.isFloat('1.2')); // true
console.log(tools.number.isFloat('eleven')); // false
Returns the float value of the parameter if it's acceptable by isFloat
, throws an Error
otherwise.
const tools = require('itaas-nodejs-tools');
console.log(tools.number.parseFloat('1.2')); // 1,2
tools.number.parseFloat('eleven'); // Error!
Under uuid
, there are UUID validation functions.
Returns true
if the string is a valid UUID, false
otherwise.
const tools = require('itaas-nodejs-tools');
console.log(tools.uuid.isUuid('6423df02-340c-11e6-ac61-9e71128cae77')); // true
console.log(tools.uuid.isUuid(null)); // false
console.log(tools.uuid.isUuid('this is not a UUID')); // false
console.log(tools.uuid.isUuid('6423df02340c11e6ac619e71128cae77')); // false
Under date
, there are some handy functions for interpreting dates, which often reach the application as strings.
Important: these functions only accept the [ISO 8601] format and use Moment strictly to validate and parse dates in that format.
Returns true
if the parameter is a valid Javascript Date
object or a string in ISO 8601 date format, false
otherwise.
const tools = require('itaas-nodejs-tools');
console.log(tools.date.isDate(new Date())); // true
console.log(tools.date.isDate('2016-06-24T23:56:37Z')); // true
console.log(tools.date.isDate('2016-06-24 23:56')); // true
console.log(tools.date.isDate('2016-06-24')); // true
console.log(tools.date.isDate(new Date('random'))); // false
console.log(tools.date.isDate(null)) // false
console.log(tools.date.isDate('24/06/2016 23:56:37')); // false
console.log(tools.date.isDate('2016-24-06')); // false
Returns a Javascript Date
object equivalent to the parameter if it's acceptable by isDate
, throws an Error
otherwise.
const tools = require('itaas-nodejs-tools');
let date = tools.date.parseDate('2016-06-24 23:56');
console.log(date.toISOString()); // 2016-06-24T23:56:00.000Z
tools.date.parseDate('2016-24-06'); // Error!
tools.date.parseDate(null); // Error!
Under httpStatus
, there are some functions that validates Http Statuses.
Returns true
if the passed status
a valid http status (between 100 and 599). Returns false
otherwise.
const tools = require('itaas-nodejs-tools');
console.log(tools.httpStatus.getClass('100')); // true
console.log(tools.httpStatus.getClass('200')); // true
console.log(tools.httpStatus.getClass('404')); // true
console.log(tools.httpStatus.getClass('451')); // true
console.log(tools.httpStatus.getClass('599')); // true
console.log(tools.httpStatus.getClass(200)); // true
console.log(tools.httpStatus.getClass(404)); // true
console.log(tools.httpStatus.getClass(0)); // false
console.log(tools.httpStatus.getClass('1')); // false
console.log(tools.httpStatus.getClass('a')); // false
console.log(tools.httpStatus.getClass('600')); // false
Returns http status type of the passed status
if it is a valid integer and is a valid http status (between 100 and 599). Throws an Error
otherwise.
const tools = require('itaas-nodejs-tools');
console.log(tools.httpStatus.getClass('100')); // 1
console.log(tools.httpStatus.getClass('200')); // 2
console.log(tools.httpStatus.getClass('404')); // 4
console.log(tools.httpStatus.getClass('451')); // 4
console.log(tools.httpStatus.getClass('599')); // 5
console.log(tools.httpStatus.getClass(200)); // 2
console.log(tools.httpStatus.getClass(404)); // 4
console.log(tools.httpStatus.getClass(0)); // Error!
console.log(tools.httpStatus.getClass('1')); // Error!
console.log(tools.httpStatus.getClass('a')); // Error!
console.log(tools.httpStatus.getClass('600')); // Error!
If is a valid http status, returns true
if the http status is 4xx, and false
otherwise. If is not a valid http status, throws an Error
(see httpStatus.getClass)
const tools = require('itaas-nodejs-tools');
console.log(tools.httpStatus.isClientError('100')); // false
console.log(tools.httpStatus.isClientError('200')); // false
console.log(tools.httpStatus.isClientError('404')); // true
console.log(tools.httpStatus.isClientError('451')); // true
console.log(tools.httpStatus.isClientError('599')); // false
console.log(tools.httpStatus.isClientError(200)); // false
console.log(tools.httpStatus.isClientError(404)); // true
console.log(tools.httpStatus.isClientError(0)); // Error!
console.log(tools.httpStatus.isClientError('1')); // Error!
console.log(tools.httpStatus.isClientError('a')); // Error!
console.log(tools.httpStatus.isClientError('600')); // Error!
If is a valid http status, returns true
if the http status is 5xx, and false
otherwise. If is not a valid http status, throws an Error
(see httpStatus.getClass)
const tools = require('itaas-nodejs-tools');
console.log(tools.httpStatus.isServerError('100')); // false
console.log(tools.httpStatus.isServerError('200')); // false
console.log(tools.httpStatus.isServerError('404')); // false
console.log(tools.httpStatus.isServerError('500')); // true
console.log(tools.httpStatus.isServerError('599')); // true
console.log(tools.httpStatus.isServerError(200)); // false
console.log(tools.httpStatus.isServerError(503)); // true
console.log(tools.httpStatus.isServerError(0)); // Error!
console.log(tools.httpStatus.isServerError('1')); // Error!
console.log(tools.httpStatus.isServerError('a')); // Error!
console.log(tools.httpStatus.isServerError('600')); // Error!
If is a valid http status, returns true
if the http status is 4xx or 5xx, and false
otherwise. If is not a valid http status, throws an Error
(see httpStatus.getClass)
const tools = require('itaas-nodejs-tools');
console.log(tools.httpStatus.isHttpError('100')); // false
console.log(tools.httpStatus.isHttpError('200')); // false
console.log(tools.httpStatus.isHttpError('400')); // true
console.log(tools.httpStatus.isHttpError('404')); // true
console.log(tools.httpStatus.isHttpError('500')); // true
console.log(tools.httpStatus.isHttpError('599')); // true
console.log(tools.httpStatus.isHttpError(200)); // false
console.log(tools.httpStatus.isHttpError(404)); // true
console.log(tools.httpStatus.isHttpError(503)); // true
console.log(tools.httpStatus.isHttpError(0)); // Error!
console.log(tools.httpStatus.isHttpError('1')); // Error!
console.log(tools.httpStatus.isHttpError('a')); // Error!
console.log(tools.httpStatus.isHttpError('600')); // Error!
This section contains middlewares for APIs built on top of Express, one of the most popular web frameworks for Node.js.
Returns an Express middleware that creates a call context for each request received.
In order to make the context available to other middlewares and to all routes, this should be the first middleware in the middleware stack and it should be applied globally, not just to a path.
This function accepts these parameters:
Parameter | Type | Required | Description | Default value |
---|---|---|---|---|
config |
object | Yes | An object containing the application configuration | - |
logger |
logger | Yes | A logger created by createLogger for the application. | - |
serviceLocator |
service locator | Yes | A service locator created by createServiceLocator | - |
setContext |
function | Yes | Function that will store the context somewhere of your choice. It must have 3 parameters: the first is the req from Express, the second is res , and the third is the context. We recommend placing the context inside the res.locals object. |
- |
The context call ID is automatically extracted from the HTTP header uux-call-context-id
if it exists. If it doesn't, a random UUID is generated for it.
The logger inside each context created by this middleware is a child of the logger specified in the parameters. Each child logs the respective call ID automatically to make it easier to track log messages from each request.
const express = require('express');
const tools = require('itaas-nodejs-tools');
let app = express();
let logger = tools.createLogger(/* ... */);
let serviceLocator = tools.createServiceLocator();
let contextMiddleware = tools.express.createCallContextMiddleware(
config,
logger,
serviceLocator,
(req, res, context) => { res.locals.context = context; }));
app.use(contextMiddleware);
// all other middlewares and routes
Returns an Express middleware that logs formatted HTTP request information at info
level. It uses Morgan to generate the formatted log message, but still uses the Bunyan logger for the actual logging.
This function accepts these parameters:
Parameter | Type | Required | Description | Default value |
---|---|---|---|---|
getLogger |
function | Yes | Function that returns the logger to be used. It can have 2 parameters: the first is the req from Express, the second is res . If the [call context middleware] is also being used, this function should return the logger within the context. |
- |
format |
string | No | The format to use for the HTTP requests log messages. It must be one of the predefined formats from Morgan | combined |
customFormatBody |
function | No | Function that will be used to customize the body formatting. It have 1 parameter, the body, and should returns the same body formated | - |
const tools = require('itaas-nodejs-tools');
let morganMiddleware = tools.express.createMorganMiddleware(
(req, res) => res.locals.context.logger, 'common', (body) => return body);
app.use(morganMiddleware);
Example of logged HTTP request (common
format):
127.0.0.1 xyz - [01/Feb/1998:01:08:39 -0800] "GET /bannerad/ad.htm HTTP/1.0" 200 198
Returns an Express middleware that changes all incoming query string parameter names to lowercase. The query string is case sensitive by standard, but case insensitivy is necessary for some APIs.
const tools = require('itaas-nodejs-tools');
let lowercaseQueryMiddleware = tools.express.createLowercaseQueryMiddleware();
app.use(lowercaseQueryMiddleware);
Example
GET www.myapi.com/users?Name=john&ORDER=age
function(req, res, next) {
// using lowercase query string names
console.log(req.param.name); // "john"
console.log(req.param.order); // "age"
}
Returns an Express middleware that removes all white space from the start and end of query string parameter values.
The middleware uses Javascript's String.prototype.trim
on each value of query string parameters.
const tools = require('itaas-nodejs-tools');
let trimQueryStringValueMiddleware = tools.express.createTrimQueryValueMiddleware();
app.use(trimQueryStringValueMiddleware);
Under promise
, there are some useful extensions to the standard Promise
API from Node.js.
Returns a Promise
that resolves as soon as one of the promises resolves, or rejects if all promises reject.
The resolution value of promise.any
is the value returned by the promise that resolved. The rejection value of promise.any
is an array of the caught errors from each promise.
Note: The errors aren't guaranteed to be in the same order as their respective promises.
const tools = require('itaas-nodejs-tools');
let promise1 = getUrl('http://www.google.com');
let promise2 = getUrl('http://www.github.com');
let promise3 = getUrl('http://www.npmjs.com');
tools.promise.any([promise1, promise2, promise3])
.then((response) => {
console.log('One of the URLs responded!');
})
.catch((errors) => {
console.log('No URLs responded!');
for (let error of errors) {
console.log(error.message);
}
});
iTaaS Node.js Tools also include command line tools for common tasks. The commands can only be executed within npm scripts.
Validates the licenses of the whole dependency tree of the package and generates a third party license compilation file with all packages and their respective licenses.
This command accepts these parameters:
Parameter | Type | Required | Description | Default value |
---|---|---|---|---|
--config |
string | No | The path of the third party license configuration file | .license-config |
--header |
string | Yes (can be specified in the config file) | A header to be added to the beginning of the third party licenses file | - |
--allow |
string | Yes (can be specified in the config file) | Comma separated list of allowed license names. An error occurs if there is any dependency with a license which is not in this list. | - |
--file |
string | Yes (can be specified in the config file) | Name of the file to be generated with the compilation of dependency licenses | - |
--skipPrefix |
string | Yes (can be specified in the config file) | The prefix of package names that must not be validated or included in the compilation file. This should be the name of the package using the license command. |
- |
The parameters can also be defined in a JSON in a configuration file. By default, a file named .license-config
is expected in the root directory of the package.
The JSON should contain these properties:
Parameter | Type | Required | Description | Default value |
---|---|---|---|---|
header |
string | Yes | A header to be added to the beginning of the third party licenses file | - |
allowedLicenseList |
array of strings | Yes | List of allowed license names. An error occurs if there is any dependency with a license which is not in this list. | - |
file |
string | Yes | Name of the file to be generated with the compilation of dependency licenses | - |
skipPrefix |
string | Yes | The prefix of package names that must not be validated or included in the compilation file. This should be the name of the package using the license command. |
- |
Using inline parameters
$ license \
--header="3RD PARTY LICENSES"
--allow=MIT,ISC,GPL,Apache-2.0
--file="3RD-PARTY-LICENSES"
--skipPrefix=my-project
Using configuration file with default name
File: ./.license-config
{
"header": "3RD PARTY LICENSES",
"allowedLicenseList": [ "MIT", "ISC", "GPL", "Apache-2.0" ],
"file": "3RD-PARTY-LICENSES",
"skipPrefix": "my-project"
}
$ license
USing configuration file with different name
File: ./license-config-tools.json
$ license --config ./license-config-tools.json