Reputation: 933
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",
}
}
));
});
Upvotes: 2
Views: 5930
Reputation: 10528
The problem is probably that you have circular imports. Your Envelope imports the user-handler and the user-handler import the Envelope. Since the Envelope is "just" an envelope, it problably shoudn't know about the user-handler. So you could refactor it in the following way:
Envelope.js
open: function(callback) {
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 callback(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"
}
});
}
}
server.js
output = input.open(UserHandler.parseEnvelope);
Now you don't need to import your user-handler.js in your Envelope.js and everything should work smoothly.
Upvotes: 2