James Legg
James Legg

Reputation: 98

Requiring modules from inside imported classes

Let's say I have the following boilerplate express app:

const express = require('express');
const app = express();
const Person = require('./controllers/person.js');


app.get('/', (req, res) => {
})

app.post('/', (req, res) => {
    var person = new Person('Bob', 'Smith');
    res.send(person.sayHello());
});

app.listen(port, () => {
    console.log('Example app listening on port ' + 3000);
})

And my person.js file looks like this:

module.exports = class Person {

   constructor(first, last) {
       this.first = first;
       this.last = last;
       this.sayHello();
   }


   sayHello() {
       return ('Hi, my name is ' + this.first + ' ' + this.last)
   }

}

Now this all works fine, but things break when I want to import modules that are just going to work on the person class.

For example, when if I change Person.sayHello() to:

async sayHello() {
       var axios = require('axios')
       var response = await axios.get('https://jsonplaceholder.typicode.com/todos/1')
       return response.title
   } 

The entire project refuses to serve requests. I have troubleshooted that the problem is the line where I require the new module, but I can't figure out another way to require that module just for that class?

Furthermore, the async isn't the issue here, if I change the sayHello() function to be:

sayHello() {
       var axios = require('axios')
       return 'This line is never returned';
}

The server still errors and a GET request gives me an ERR_CONNECTION_REFUSED

Upvotes: 0

Views: 54

Answers (1)

Callam
Callam

Reputation: 11539

You are passing the result of person.sayHello() to res.send, however, because sayHello is an async function, you need to then or await it to get the result of the Promise. The functions also called in your Person constructor, without executing the Promise. I presume it is reduntant since you're calling the function in your express app after initiating a person.

app.post('/', async (req, res) => {
  const person = new Person('Bob', 'Smith');

  try {
    res.send(await person.sayHello());
  } catch(error) {
    res.send(error.message || `${error}`);
  }
});

You will also find that the response from axios doesn't have a title property, you need can access it by response.data.title.

module.exports = class Person {
  constructor(first, last) {
    this.first = first;
    this.last = last;
  }

  async sayHello() {
    const axios = require('axios');
    const response = await axios.get(
      'https://jsonplaceholder.typicode.com/todos/1'
    );

    return response.data.title;
  }
}

Not sure if you have removed the implementation of your get request in the express app from the question or if you don't actually have one yet. If that's the case, it will timeout on a GET request to /.

const express = require('express');
const app = express();
const Person = require('./controllers/person.js');

app.get('/', (req, res) => {
  res.send('Hello, World!');
})

app.post('/', async (req, res) => {
  const person = new Person('Bob', 'Smith');
  res.send(await person.sayHello());
});

app.listen(3000, () => {
  console.log('Example app listening on port ' + 3000);
})

Anyway, using the two previous blocks of code, I was able to succeed in requiring axios inside the sayHello function and return the title of the response data. I cannot however reproduce the problem you're describing, with the exception of the timeout as a result of the empty route.

Upvotes: 1

Related Questions