I'm building a simple server in JavaScript running on the Node.js platform. The server accepts JavaScript Objects, parses them, and executes commands based on what it finds; fairly simple stuff. I call those Objects Envelopes (because you open up envelopes in real life and do things based on what they say. Get it? I'm so clever.).
I have 3 files which are called: server.js, envelope.js, and user-handler.js. In my tests, the user sends a "user" Envelope for the server to parse, eventually so the server creates a new user and adds them into the MongoDB instance I've set up locally.
However, in user-handler.js, I've encountered a weird error: TypeError: object is not a function. I have no idea why I'm getting this error, because the Envelope object is definitely being imported correctly. Below you'll find the 3 files in question. Any and all answers are greatly appreciated!
EDIT: For clarification, here is the exact stacktrace that I get when running a test (which I've also included):
Server listening on port 31337
Accepted input from user...
Opened up the envelope...
[Function: Envelope]
Envelope verified successfully
It's a 'user' command...
Starting to parse the envelope...
Going to create a new user...
Now to save new user...
/home/ME/PROJECT/lib/user-handler.js:52
console.log(new Envelope({
^
TypeError: object is not a function
at Object.module.exports.parseEnvelope (/home/ME/PROJECT/lib/user-handler.js:52:19)
at Envelope.open (/home/ME/PROJECT/lib/envelope.js:34:28)
at Socket.<anonymous> (/home/ME/PROJECT/lib/server.js:22:22)
at Socket.EventEmitter.emit (events.js:95:17)
at Socket.<anonymous> (_stream_readable.js:720:14)
at Socket.EventEmitter.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:392:10)
at emitReadable (_stream_readable.js:388:5)
at readableAddChunk (_stream_readable.js:150:9)
at Socket.Readable.push (_stream_readable.js:113:10)
server.js
"use strict";
var net = require("net")
, mongoose = require("mongoose")
, dbConf = require("../conf")
, Envelope = require("./envelope")
, UserHandler = require("./user-handler")
, uri, db, server;
uri = (dbConf.uri || "mongodb://localhost") // URI
+ (":" + (dbConf.port || 27017) + "/") // Port
+ (dbConf.db || "DATABASE"); // Database
db = mongoose.connect(uri);
server = net.createServer(function(socket) {
socket.on("data", function(data) {
var input, output;
//try {
input = new Envelope(JSON.parse(data.toString()));
console.log("Accepted input from user...");
output = input.open();
console.log("And the output is: ");
/*} catch (error) {
var errorString = String(error).split(": ");
output = new Envelope({
header: {
type: "error"
},
body: {
errorType: errorString[0],
errorMessage: errorString[1]
}
});
}*/
console.log(JSON.stringify(output));
});
});
server.listen(31337, function() {
console.log("Server listening on port 31337");
});
envelope.js
"use strict";
var userHandler = require("./user-handler");
var Envelope = function Envelope(data) {
for (var key in data) {
this[key] = data[key];
}
};
Envelope.prototype = {
constructor: Envelope,
verify: function() {
console.log(this.constructor);
if (this.header && this.header.type && this.body) {
console.log("Envelope verified successfully");
return true;
} else {
console.log("Envelope did not verify successfully");
return false;
}
},
open: function() {
var self = this;
console.log("Opened up the envelope...");
if (self.verify()) {
switch (self.header.type) {
case "user":
console.log("It's a 'user' command...");
return userHandler.parseEnvelope(self);
break;
default:
return new Envelope({
header: {
type: "empty"
}
});
}
} else {
return new Envelope({
header: {
type: "error"
},
body: {
errorType: "MissingDataError",
errorMessage: "Missing either: header, body, or header.type"
}
});
}
}
};
module.exports = Envelope;
user-handler.js
"use strict";
var User = require("../models/user")
, Envelope = require("./envelope");
module.exports = {
parseEnvelope: function(env) {
var header = env.header;
var body = env.body;
console.log("Starting to parse the envelope...");
switch (header.method) {
case "create":
console.log("Going to create a new user...");
var newName = body.name || {
first: "",
last: ""
};
var newUser = new User({
username: body.username,
password: body.password,
name: newName,
email: body.email || ""
});
console.log("Now to save new user...");
/*newUser.save(function(err) {
if (err) {
console.log("Ruh roh, there was an error...");
console.log(String(err));
} else {
console.log("New user saved successfully to the database...");
return newUser;
}
});*/
/*var response = new Envelope({
header: {
type: "response",
requestType: "user",
requestMethod: "create"
},
body: {
_id: newUser._id,
username: newUser.username,
password: newUser.password,
name: newUser.name,
email: newUser.email
}
});*/
console.log(new Envelope({
test: "Hello, world!"
}));
//console.log(response);
break;
default:
return new Envelope({
header: {
type: "error"
},
body: {
error: "MissingHeaderMethodError",
errorMessage: "Missing header parameter: method"
}
});
break;
}
}
};
tests/user.js
"use strict";
var net = require("net")
, client;
client = net.connect({host: "localhost", port: 31337}, function() {
client.end(JSON.stringify(
{
"header": {
"type": "user",
"method": "create"
},
"body": {
"username": "john_doe",
"password": "password1",
}
}
));
});
exportsobject. I know that's allowed, but consider that NodeJS caches theexportsobject so that you don't keep parsing the same module every time it's requested. Now consider the orderserver -> Envelope -> user-handler -> Envelope. Whenuser-handlerrequests theEnvelope, the parsing ofEnvelopehas already started, so NodeJS won't start it again, but it does need to return something, so it returns the defaultexportsobject because you've not yet replaced it at the bottom of theEnvelopemodule.