Z. Charles Dziura
Z. Charles Dziura

Reputation: 933

Getting weird "TypeError: object is not a function" in Node, when the object is clearly defined

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

Answers (1)

basilikum
basilikum

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

Related Questions