├── .babelrc ├── .gitignore ├── LICENSE ├── README.md ├── package.json └── scripts ├── index.js └── plugin-request.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | "plugins": ["transform-es2015-modules-umd"] 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | 4 | #IDE 5 | .idea 6 | *.iml 7 | 8 | #Deps 9 | node_modules 10 | bower_components 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Backbase 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #mosaic-rest-js 2 | 3 | ### About 4 | This is a js library for Backbase [REST API](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest.html). 5 | 6 | ## Example: 7 | 8 | #### nodejs 9 | 10 | ``` javascript 11 | var BBRest = require('mosaic-rest-js'), 12 | var bbrest = new BBRest({ 13 | portal: 'myPortal' 14 | }); 15 | ``` 16 | 17 | #### AMD module 18 | 19 | ``` javascript 20 | require(['bbrest'], function(BBRest) { 21 | var bbrest = new BBRest({ 22 | portal: 'myPortal' 23 | }); 24 | }) 25 | ``` 26 | 27 | ``` javascript 28 | // list portals 29 | bbrest.server().get().then(function(value) { 30 | if (value.statusCode === 200) { 31 | console.log('Response OK'); 32 | } 33 | }); 34 | 35 | // add portal 36 | bbrest.server().post('addPortal.xml').then(function(d) { 37 | console.log(d); 38 | }); 39 | 40 | // update portal 41 | bbrest.server().put('updatePortal.xml').then(function(d) { 42 | console.log(d); 43 | }); 44 | 45 | // list 5 items from catalog 46 | bbrest.catalog().query({ps:5}).get().then(function(d) { 47 | console.log(d); 48 | }); 49 | ``` 50 | 51 | ## Automation: 52 | 53 | ``` 54 | npm install // install nodejs dependencies 55 | bower install // install bower dependecies 56 | gulp node // build node distribution file 57 | gulp jquery // build browser jQuery based ditribution file 58 | gulp angular // build browser Angular based ditribution file 59 | gulp min // minify browser distribution files 60 | gulp test-node // run node tests (requires running portal) 61 | gulp test-jq // run jQuery phantomjs tests (requires running portal) 62 | gulp test-ng // run Angular phantomjs tests (requires running portal) 63 | ``` 64 | 65 | ## BBRest methods 66 | #### constructor(config:Object) 67 | BBRest Constructor. 68 | - config - *extends default configuration* 69 | 70 | **configuration defaults:** 71 | 72 | ``` javascript 73 | { 74 | scheme: 'http', 75 | host: 'localhost', 76 | port: '7777', 77 | context: 'portalserver', 78 | username: 'admin', 79 | password: 'admin', 80 | portal: null // name of the targeted portal, 81 | plugin: null // function to pre-process data 82 | } 83 | ``` 84 | 85 | #### server() 86 | Prepares request on server domain. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_portal.html) 87 | - *returns* instance of the [BBReq](#BBReq) 88 | 89 | Valid Requests, returning promises: 90 | 91 | ``` javascript 92 | bbrest.server().get(); // returns list of portals 93 | bbrest.server().post('path.to.xml'); // creates a portal 94 | bbrest.server().put('path.to.xml'); // updates portal(s) 95 | ``` 96 | 97 | #### portal() 98 | Prepares request on portal domain. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_portal.html) 99 | - *returns* instance of the [BBReq](#BBReq) 100 | 101 | Valid Requests, returning promises: 102 | 103 | ``` javascript 104 | bbrest.portal().put('path.to.xml'); // updates portal 105 | bbrest.portal().delete(); // deletes the portal 106 | 107 | bbrest.portal().get(); // returns portal data 108 | 109 | bbrest.portal().rights().get(); // returns portal rights 110 | bbrest.portal().rights().put('path.to.xml'); // updates portal rights 111 | 112 | bbrest.portal().tags().get(); // returns portal tags 113 | bbrest.portal().tags().post('path.to.xml'); // creates a tag 114 | bbrest.portal().tags('myTag').delete(); // deletes a tag 115 | ``` 116 | #### catalog(item) 117 | Prepares request on server catalog. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_portal.html) 118 | - **item** - name of the item in server catalog 119 | - *returns* instance of the [BBReq](#BBReq) 120 | 121 | Valid Requests, returning promises: 122 | 123 | ``` javascript 124 | bbrest.catalog().get(); // returns server catalog 125 | bbrest.catalog().post('path.to.xml'); // add item(s) to server catalog 126 | bbrest.catalog().put('path.to.xml'); // updates item(s) in server catalog 127 | bbrest.catalog().delete('path.to.xml'); // batch delete items from the server catalog 128 | 129 | bbrest.catalog('myItem').get(); // returns item from the server catalog 130 | bbrest.catalog('myItem').delete(); // deletes item from the server catalog 131 | ``` 132 | #### portalCatalog(item) 133 | Prepares request on portal catalog. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_portal.html) 134 | - **item** - name of the item in porta catalog 135 | - *returns* instance of the [BBReq](#BBReq) 136 | 137 | Valid Requests, returning promises: 138 | 139 | ``` javascript 140 | bbrest.portalCatalog().get(); // returns portal catalog 141 | bbrest.portalCatalog().post('path.to.xml'); // add item(s) to portal catalog 142 | bbrest.portalCatalog().put('path.to.xml'); // updates item(s) in portal catalog 143 | bbrest.portalCatalog().delete('path.to.xml'); // batch delete items from the portal catalog 144 | 145 | bbrest.portalCatalog('myItem').get(); // returns item from the portal catalog 146 | bbrest.portalCatalog('myItem').delete(); // deletes item from the portal catalog 147 | ``` 148 | 149 | #### page(name:String) 150 | Prepares page request. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_page.html) 151 | - **name** - name of the page to target 152 | - *returns* instance of the [BBReq](#BBReq) 153 | 154 | Valid Requests, returning promises: 155 | 156 | ``` javascript 157 | bbrest.page().get(); // returns portal pages 158 | bbrest.page().post('path.to.xml'); // creates page(s) 159 | bbrest.page().put('path.to.xml'); // updates page(s) 160 | 161 | bbrest.page('name').get(); // returns page 162 | bbrest.page('name').put('path.to.xml'); // updates page 163 | bbrest.page('name').delete(); // deletes page 164 | 165 | bbrest.page('name').rights().get(); // returns page rights 166 | bbrest.page('name').rights().put('path.to.xml'); // updates page rights 167 | ``` 168 | 169 | #### container(name:String) 170 | Prepares container request. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_pcat_cont.html) 171 | - **name** - name of the container to target 172 | - *returns* instance of the [BBReq](#BBReq) 173 | 174 | Valid Requests, returning promises: 175 | 176 | ``` javascript 177 | bbrest.container().get(); // returns portal containers 178 | bbrest.container().post('path.to.xml'); // creates a container(s) 179 | bbrest.container().put('path.to.xml'); // updates container(s) 180 | 181 | bbrest.container('name').get(); // returns container 182 | bbrest.container('name').put('path.to.xml'); // updates container 183 | bbrest.container('name').delete(); // deletes container 184 | 185 | bbrest.container('name').rights().get(); // returns container rights 186 | bbrest.container('name').rights().put('path.to.xml'); // updates container rights 187 | ``` 188 | 189 | #### widget(name:String) 190 | Prepares widget request. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_pcat_widg.html) 191 | - **name** - name of the widget to target 192 | - *returns* instance of the [BBReq](#BBReq) 193 | 194 | Valid Requests, returning promises: 195 | 196 | ``` javascript 197 | bbrest.widget().get(); // returns portal widgets 198 | bbrest.widget().post('path.to.xml'); // creates a widget(s) 199 | bbrest.widget().put('path.to.xml'); // updates widget(s) 200 | 201 | bbrest.widget('name').get(); // returns widget 202 | bbrest.widget('name').put('path.to.xml'); // updates widget 203 | bbrest.widget('name').delete(); // deletes widget 204 | 205 | bbrest.widget('name').rights().get(); // returns widget rights 206 | bbrest.widget('name').rights().put('path.to.xml'); // updates widget rights 207 | ``` 208 | 209 | #### link(name:String) 210 | Prepares link request. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_link.html) 211 | - **name** - name of the link to target 212 | - *returns* instance of the [BBReq](#BBReq) 213 | 214 | Valid Requests, returning promises: 215 | 216 | ``` javascript 217 | bbrest.link().get(); // returns portal links 218 | bbrest.link().post('path.to.xml'); // creates link(s) 219 | bbrest.link().put('path.to.xml'); // updates link(s) 220 | 221 | bbrest.link('name').get(); // returns link 222 | bbrest.link('name').put('path.to.xml'); // updates link 223 | bbrest.link('name').delete(); // deletes link 224 | 225 | bbrest.link('name').rights().get(); // returns link rights 226 | bbrest.link('name').rights().put('path.to.xml'); // updates link rights 227 | ``` 228 | 229 | #### template(name:String) 230 | Prepares template request. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_template.html) 231 | - **name** - name of the template to target 232 | - *returns* instance of the [BBReq](#BBReq) 233 | 234 | Valid Requests, returning promises: 235 | 236 | ``` javascript 237 | bbrest.template().get(); // returns portal templates 238 | bbrest.template().post('path.to.xml'); // creates template(s) 239 | 240 | bbrest.template('name').get(); // returns template 241 | bbrest.template('name').put('path.to.xml'); // updates template 242 | 243 | bbrest.template('name').rights().get(); // returns template rights 244 | bbrest.template('name').rights().put('path.to.xml'); // updates template rights 245 | ``` 246 | 247 | #### user(name:String, showGroups:Boolean, groupName:String) 248 | Prepares user request. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_user.html) 249 | - **name** - name of the user to target 250 | - **showGroups** - if true, user groups are targeted 251 | - **groupName** - name of the group to delete user from 252 | - *returns* instance of the [BBReq](#BBReq) 253 | 254 | Valid Requests, returning promises: 255 | 256 | ``` javascript 257 | bbrest.user().get(); // returns list of users 258 | bbrest.user().post('path.to.xml'); // creates a user 259 | 260 | bbrest.user('user').get(); // returns user 261 | bbrest.user('user').put('path.to.xml'); // updates user 262 | bbrest.user('user').delete(); // deletes user 263 | 264 | bbrest.user('user', true).get(); // returns groups that user belongs to 265 | bbrest.user('user', true).post('path.to.xml'); // adds user to group(s) 266 | bbrest.user('user', true, 'group').delete(); // removes user from a group 267 | ``` 268 | 269 | #### group(name:String, showUsers:Boolean) 270 | Prepares group request. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_group.html) 271 | - **name** - name of the group to target 272 | - **showUsers** - if true, group's users are targeted 273 | - *returns* instance of the [BBReq](#BBReq) 274 | 275 | Valid Requests, returning promises: 276 | 277 | ``` javascript 278 | bbrest.group().get(); // returns list of groups 279 | bbrest.group().post('path.to.xml'); // creates a group 280 | 281 | bbrest.group('group').get(); // returns group 282 | bbrest.group('group').put('path.to.xml'); // updates group 283 | bbrest.group('group').delete(); // deletes group 284 | 285 | bbrest.group('group', true).get(); // returns users that belong to a group 286 | bbrest.group('group', true).post('path.to.xml'); // adds user(s) to group 287 | bbrest.group('group', true, 'user').delete(); // removes user from a group 288 | ``` 289 | 290 | #### audit(meta:Boolean) 291 | Prepares audit trails request. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_audit.html) 292 | - **meta** - if true, targets audit metadat, otherwise it targets audit events 293 | - *returns* instance of the [BBReq](#BBReq) 294 | 295 | Valid Requests, returning promises: 296 | 297 | ``` javascript 298 | bbrest.audit().get(); // returns auditEvents 299 | bbrest.audit(true).get(); // returns auditMetaData 300 | ``` 301 | 302 | #### cache(type:String) 303 | Prepares cache request. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_caches.html) 304 | - **type** - possible values: global, widget, chrome, closure, url, web, gmodel 305 | - *returns* instance of the [BBReq](#BBReq) 306 | 307 | Valid Requests, returning promises: 308 | 309 | ``` javascript 310 | bbrest.cache('all').delete(); // sends all of the below requests one by one 311 | 312 | bbrest.cache('globalModelCache').delete(); 313 | bbrest.cache('retrievedWidgetCache').delete(); 314 | bbrest.cache('widgetChromeStaticCache').delete(); 315 | bbrest.cache('serverSideClosureCache').delete(); 316 | bbrest.cache('urlLevelCache').delete(); 317 | bbrest.cache('webCache').delete(); 318 | bbrest.cache('gModelCache').delete(); 319 | bbrest.cache('uuidFromExtendedItemNamesCache').delete(); 320 | bbrest.cache('springAclSidCacheRegion').delete(); 321 | bbrest.cache('contextNameToItemNameToUuidCache').delete(); 322 | bbrest.cache('widgetCache').delete(); 323 | bbrest.cache('uuidToContentReferencesCache').delete(); 324 | bbrest.cache('springAclCacheRegion').delete(); 325 | bbrest.cache('itemUuidToReferencingLinkUuidsCache').delete(); 326 | bbrest.cache('uuidToCacheKeysCache').delete(); 327 | bbrest.cache('versionBundleCache').delete(); 328 | ``` 329 | You can [get bookmarklet](http://goo.gl/YqOrp8) to delete all caches at once. 330 | #### auto(data) 331 | Performs POST or PUT request by finding the right BBRest method from the data. 332 | - **data** - if string, represents path of the xml file which content will be sent. If object, it is first sent to config.plugin function 333 | - *returns* promise with response value 334 | 335 | Valid Request, returning promises: 336 | 337 | ``` javascript 338 | bbrest.auto('path.to.xml'); 339 | ``` 340 | 341 | #### import() 342 | Imports portal. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1/refc_rest_import.html) 343 | - *returns* instance of the [BBReq](#BBReq) 344 | 345 | Valid Requests, returning promises: 346 | 347 | ``` javascript 348 | bbrest.import().post('path.to.xml'); // imports xml 349 | bbrest.import().file('/path/to/exported.zip').post(); // uploads and imports zip archive 350 | ``` 351 | 352 | #### export(uuid:String) 353 | Exports portal. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1/refc_rest_export.html) 354 | - **uuid** - id of the exported file on the server. Use when you need to download file 355 | - *returns* instance of the [BBReq](#BBReq) 356 | 357 | To get archive of the portal from the server, you need to make 2 requests. 358 | In first one, we send [type of export](https://my.backbase.com/resources/documentation/portal/5.5.1/refc_pxsd_elmt_xreq.html) and get back the id of exported archive in response. 359 | With second request we pass that id and local path where archive will be downloaded. 360 | 361 | Valid Requests, returning promises: 362 | 363 | ``` javascript 364 | // export as xml in response 365 | bbrest.export().get(); 366 | // prepare file export 367 | bbrest.export().post('path.to.xml').then(data) { 368 | // data is xml or js object if plugin is used 369 | var id = data.body.exportResponse.identifier; // get id of the archive 370 | return bbrest.export(id).file('local.path.zip').get(); // returns promise 371 | } 372 | ``` 373 | 374 | ## BBReq methods 375 | #### rights() 376 | Modifies request to target rights. 377 | - *returns* instance of the [BBReq](#BBReq) 378 | 379 | #### tag(name:String) 380 | Modifies request to target tags 381 | - *returns* instance of the [BBReq](#BBReq) 382 | 383 | ### query(obj:Object) 384 | Defines modifiers. [API Reference](https://my.backbase.com/resources/documentation/portal/5.5.1.0/refc_rest_urlmod.html) 385 | - **obj** - object with querystring values to be appended to the uri 386 | - *returns* instance of the [BBReq](#BBReq) 387 | 388 | #### file(path:String) 389 | Defines path to the file where export is downloaded. 390 | - *returns* instance of the [BBReq](#BBReq) 391 | 392 | #### get() 393 | Performs GET request 394 | - *returns* promise with response value 395 | 396 | #### post(data) 397 | Performs POST request 398 | - **data** - if string, represents path of the xml file which content will be sent. If object, it is first sent to config.plugin function 399 | - *returns* promise with response value 400 | 401 | ``` javascript 402 | bbrest.config.plugin = function(data) { 403 | return jxon.jsToString(data); // converts js object in jxon notation to XML string which will be posted 404 | } 405 | bbrest.widget('myWidget').post(jxonObj); 406 | ``` 407 | 408 | #### put(data) 409 | Performs PUT request 410 | - **data** - if string, represents path of the xml file which content will be sent. If object, it is first sent to config.plugin function 411 | - *returns* promise with response value 412 | 413 | #### delete(data) 414 | Performs DELETE request 415 | - **data** - if string, represents path of the xml file which content will be sent. If object, it is first sent to config.plugin function 416 | - *returns* promise with response value 417 | 418 | **response value:** 419 | 420 | ``` javascript 421 | { 422 | error: // true if is error 423 | statusCode: // http status code 424 | statusInfo: // http status code description or error infor 425 | body: // contains body of the server response, 426 | href: // request location, 427 | method: // request method, 428 | reqBody: // request body, 429 | file: // file name, 430 | headers: // response headers 431 | } 432 | ``` 433 | 434 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mosaic-rest-js", 3 | "version": "1.0.1", 4 | "description": "nodejs library for Backbase REST API", 5 | "main": "scripts/index.js", 6 | "keywords": [ 7 | "backbase", 8 | "rest api" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/Backbase/mosaic-rest-js.git" 13 | }, 14 | "homepage": "https://github.com/Backbase/mosaic-rest-js.git", 15 | "bugs": "https://github.com/Backbase/mosaic-rest-js/issues", 16 | "author": "Igor Dimitrijevic", 17 | "dependencies": { 18 | "lib-bb-portal-rest": "^0.1.1", 19 | "q": "^1.4.1", 20 | "request": "^2.74.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/index.js: -------------------------------------------------------------------------------- 1 | var BBRest = require('lib-bb-portal-rest').default; 2 | var plugin = require('./plugin-request'); 3 | 4 | module.exports = function(config) { 5 | config.plugin = plugin; 6 | return new BBRest(config); 7 | } 8 | -------------------------------------------------------------------------------- /scripts/plugin-request.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var fs = require('fs'); 3 | var url = require('url'); 4 | var Q = require('q'); 5 | var util = require('util'); 6 | 7 | var sessionHeaders; 8 | 9 | exports.get = function(filePath) { 10 | var defer = Q.defer; 11 | fs.readFile(filePath, function (err, buf) { 12 | if (err) defer.reject(err); 13 | else defer.resolve(buf.toString()); 14 | }); 15 | return defer.promise; 16 | } 17 | 18 | function getSessionHeaders(config, log) { 19 | var defer = Q.defer(); 20 | if (sessionHeaders) defer.resolve(sessionHeaders); 21 | else { 22 | var base64 = new Buffer(config.username + ':' + config.password, 'utf8') 23 | .toString('base64'); 24 | var headers = { 25 | Authorization: 'Basic ' + base64, 26 | }; 27 | log('Session Request Configuration', {url: config.url, method: 'HEAD', headers: headers}); 28 | // can we use head method? 29 | request({ 30 | url: config.url, 31 | method: 'HEAD', 32 | headers: headers 33 | }, function(err, res) { 34 | if (err) defer.reject(err); 35 | else { 36 | sessionHeaders = { 37 | Cookie: res.headers['set-cookie'] 38 | } 39 | const csrf = res.headers['x-bbxsrf']; 40 | if (csrf) sessionHeaders['X-BBXSRF'] = csrf; 41 | 42 | defer.resolve(sessionHeaders); 43 | } 44 | }); 45 | } 46 | return defer.promise; 47 | } 48 | function parseResponse(res, isDownload) { 49 | return { 50 | status: res.statusCode, 51 | statusText: res.statusMessage, 52 | headers: res.headers, 53 | body: isDownload ? '' : res.body.toString() 54 | }; 55 | } 56 | 57 | /** 58 | * config properties: 59 | * url - string - url to call 60 | * method - string - http method 61 | * query - object - query hash 62 | * headers - object - headers hash 63 | * body - string - body to send 64 | * username - string - username 65 | * password - string - password 66 | * file - string - file path for upload/download 67 | * upload - string - name of the form field for upload 68 | * download - boolean - true if response is stream to download 69 | */ 70 | exports.request = function(config, log) { 71 | return getSessionHeaders(config, log) 72 | .then(function(headers) { 73 | Object.assign(config.headers, headers); 74 | 75 | var options = { 76 | method: config.method, 77 | uri: config.url, 78 | headers: config.headers, 79 | body: config.body, 80 | qs: config.query 81 | } 82 | log('Request Configuration', config); 83 | if (config.file && !config.download) { 84 | options.formData = {}; 85 | options.formData[config.upload] = fs.createReadStream(config.file); 86 | } 87 | 88 | var defer = Q.defer(); 89 | 90 | var req = request(options, 91 | function(err, res) { 92 | if (err) defer.reject(err); 93 | else { 94 | defer.resolve(parseResponse(res, config.download)); 95 | } 96 | } 97 | ); 98 | if (config.download) req.pipe(fs.createWriteStream(config.file)); 99 | return defer.promise; 100 | }); 101 | } 102 | 103 | exports.urlParse = function(urlString) { 104 | return url.parse(urlString, true); 105 | } 106 | 107 | exports.log = function(title, obj) { 108 | console.log('\n-------------------------\n' + title + '\n-------------------------'); 109 | console.log(util.inspect(obj, { 110 | depth: 4, 111 | colors: true 112 | })); 113 | } 114 | 115 | --------------------------------------------------------------------------------