Below is the Node.js project
api
swagger.yaml - having visual representation of the API and its documentation
controllers
entityApi.js file - APIs - create,delete,list,patch api
service
entityService.js - API implementation
utils
mongoUtils.js
index.js file
.... and other files
Below is the code in zindex.js` file:
'use strict';
const fs = require('fs'),
path = require('path'),
http = require('http'),
mongoUtils = require('./utils/mongoUtils'),
swaggerUtils = require('./utils/swaggerUtils');
const {error, errorEnum, sendError} = require('./utils/errorUtils');
const app = require('connect')();
const swaggerTools = require('swagger-tools');
const serverPort = 8080;
//error is coming here
fs.copyFileSync(path.join(__dirname, './index.html_replacement'),
path.join(__dirname, './node_modules/swagger-ui-dist/index.html'), (err) => {
if(err) {
console.log('Unable to replace swagger-ui-dist/index.html file - something wrong with the installation ??');
process.exit(1);
}
})
// swaggerRouter configuration
const options = {
swaggerUi: path.join(__dirname, '/swagger.json'),
controllers: path.join(__dirname, './controllers'),
useStubs: process.env.NODE_ENV === 'development' // Conditionally turn on stubs (mock mode)
};
const swaggerDoc = swaggerUtils.getSwaggerDoc();
swaggerTools.initializeMiddleware(swaggerDoc, function (middleware) {
app.use(middleware.swaggerMetadata());
// Validate Swagger requests
app.use(middleware.swaggerValidator({
validateResponse: false
}));
// Error handling for validation
app.use(errorHandler);
// Route validated requests to appropriate controller
app.use(middleware.swaggerRouter(options));
// Serve the Swagger documents and Swagger UI
// using the more up-to-date swagger-ui-dist - not the default app.use(middleware.swaggerUi())
app.use(middleware.swaggerUi({ swaggerUiDir: path.join(__dirname, 'node_modules', 'swagger-ui-dist') }));
// Start the server
http.createServer(app).listen(serverPort, function () {
console.log('Your server is listening on port %d (http://localhost:%d)', serverPort, serverPort);
console.log('Swagger-ui is available on http://localhost:%d/docs', serverPort);
});
});
// handles timed out requests
function haltOnTimedout(req, res, next) {
if (!req.timedout) {
next();
} else {
debug("\nrequest timed out!\n");
next("the request timed out", null, null, null, 504);
}
}
function errorHandler (err, req, res, next) {
if(err) {
if(err.failedValidation) {
const message = err.results.errors.map(item => item.message).join(", ");
const error = new Error(ErrorEnum.INVALID_BODY, message);
sendError(res,error);
} else {
const error = new Error(ErrorEnum.INVALID_BODY, "Invalid request");
sendError(res,error);
}
} else {
next(err,req,res);
}
};
and mongoUtils.js
contents below:
'use strict';
const util = require('util')
const assert = require('assert');
const queryToMongo = require('query-to-mongo');
const querystring = require('querystring');
const MongoClient = require('mongodb').MongoClient;
const {getResponseType, getPayloadType, getTypeDefinition} = require('./swaggerUtils');
var mongodb = null;
function connectHelper(callback) {
var config = require('../config.json');
var argv = require('minimist')(process.argv);
var dbhost = argv.dbhost ? argv.dbhost: config.db_host;
const mongourl = process.env.MONGO_URL || (config.db_prot + "://" + dbhost + ":" + config.db_port + "/" + config.db_name);
MongoClient.connect(mongourl, { useNewUrlParser: true }, function (err, db) {
if (err) {
mongodb = null;
callback(err,null);
} else {
mongodb = db.db("mydatabase");
callback(null,mongodb);
}
}
);
};
function getMongoQuery(req) {
var res;
if(req instanceof Object) {
res = queryToMongo(req._parsedUrl.query);
} else {
res = queryToMongo(querystring.parse(req));
}
if(res!==undefined && res.options!==undefined && res.options.fields!==undefined) {
res.options.fields.href = true;
res.options.fields.id = true;
}
try {
const requestType = getPayloadType(req);
const properties = Object.keys(res.criteria);
var typeDefinition = getTypeDefinition(requestType);
if(typeDefinition.properties!==undefined) {
typeDefinition = typeDefinition.properties;
}
properties.forEach(prop => {
var paramDef = typeDefinition[prop];
if(paramDef!==undefined && paramDef.type === "string" && paramDef.format === "date-time") {
const propVal = res.criteria[prop];
// equality test if not the value is an object
if(!(propVal instanceof Object)) {
if(!isNaN(Date.parse(propVal))) {
res.criteria[prop] = {$regex: '^' + propVal + '.*' };
}
}
}
});
}
catch(err) {
// ignore for now
}
res.options.projection = res.options.fields;
delete res.options.fields;
return(res);
};
function quotedString(s) {
return s;
};
function connectDb(callback) {
if(mongodb) {
mongodb.stats(function(err, stats) {
if(stats != null) {
callback(null,mongodb);
} else {
connectHelper(callback);
}
});
} else {
connectHelper(callback);
}
};
function connect() {
return new Promise(function(resolve,reject) {
connectDb(function(err,db) {
if(err!=null || db==null) {
reject(err);
} else {
resolve(db);
};
});
});
};
function sendDoc(res,code,doc) {
// delete internal mongo _id from all documents
if(Array.isArray(doc)) {
// remove _id from all documents
doc.forEach(x => {
delete x._id;
});
} else {
delete doc._id;
}
if(doc.href) {
res.setHeader('Location', doc.href);
}
res.statusCode = code;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(doc));
}
module.exports = { connect, connectDb, getMongoQuery, sendDoc };
the npm install is fine whereas node index.js gives below error
binding.copyFile(
** ^
TypeError: mode must be int32 or null/undefined
at Object.copyFileSync (node:fs:3086:11)
at Object.<anonymous> (C:\Users\shivashankar.g02\<<project path>>\index.js:18:4) at Module._compile (node:internal/modules/cjs/loader:1562:14)
**
at Object..js (node:internal/modules/cjs/loader:1699:10)
at Module.load (node:internal/modules/cjs/loader:1313:32)
at Function._load (node:internal/modules/cjs/loader:1123:12)
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:217:24)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:170:5)
at node:internal/main/run_main_module:36:49 {
code: 'ERR_INVALID_ARG_TYPE'
Any pointers/directions on why it's happening?
copyFileSync
takes three arguments - the source, the destination and an optional mode
integer mask. Your third argument is a callback, which causes this error.
Since you're passing a callback, it seems like you meant to use copyFile
, not copyFileSync
:
fs.copyFile(
path.join(__dirname, './index.html_replacement'),
path.join(__dirname, './node_modules/swagger-ui-dist/index.html'),
(err) => {
if(err) {
console.log('Unable to replace swagger-ui-dist/index.html file - something wrong with the installation ??');
process.exit(1);
}
}
)
For the record, copyFile
can also take a mode
argument, but like with copyFileSync
, this argument can be omitted.