0

I have a business leve database module called "db_location" which uses the node-fetch module to get some data from a remote server via REST API.

**db_location.js** DB LOGIC

const p_conf = require('../parse_config');

const db_location = {
    getLocations: function() {

        fetch(`${p_conf.SERVER_URL}/parse` + '/classes/GCUR_LOCATION', { method: 'GET', headers: {
            'X-Parse-Application-Id': 'APPLICATION_ID',
            'X-Parse-REST-API-Key': 'restAPIKey'
        }})
        .then( res1 => {
            //console.log("res1.json(): " + res1.json());
            return res1;
        })
        .catch((error) => {
            console.log(error);
            return Promise.reject(new Error(error));
        })
    }

};

module.exports = db_location

I would need to call this function within a Route function so as to separate database processing from controller.

**locations.js** ROUTE

var path = require('path');
var express = require('express');
var fetch = require('node-fetch');
var router = express.Router();

const db_location = require('../db/db_location');

/* GET route root page. */
router.get('/', function(req, res, next) {

  db_location.getLocations()
  .then(res1 => res1.json())
  .then(json => res.send(json["results"]))
  .catch((err) => {
    console.log(err);
    return next(err);
  })
});

When I ran http://localhost:3000/locations, I received the following error.

Cannot read property 'then' of undefined

TypeError: Cannot read property 'then' of undefined

It seems the Promise was empty or something wrong down the Promise chain going from one response object to another? What is a best practise for solving this kind of scenario?

EDIT 1

If I changed the getLocations to return res1.json() (which I think is a non-empty Promise according to the node-fetch documentation):

fetch(`${p_conf.SERVER_URL}/parse` + '/classes/GCUR_LOCATION', { method: 'GET', headers: {
        'X-Parse-Application-Id': 'APPLICATION_ID',
        'X-Parse-REST-API-Key': 'restAPIKey'
    }})
    .then(  res1 => {
       return res1.json();     // Not empty as it can be logged to `Promise Object`
    })
    .catch((error) => {
        console.log(error);
        return Promise.reject(new Error(error));
    })

And the route code was changed to :

db_location.getLocations()
  .then(json => res.send(json["results"]))
  .catch((err) => {
    console.log(err);
    return next(err);
  })

The exactly same error was thrown.

alextc
  • 3,206
  • 10
  • 63
  • 107

2 Answers2

2

You need getLocations to return a Promise. At the moment, it's running a fetch, but that fetch isn't connected to anything else, and getLocations is returning undefined (and of course you can't call .then on uundefined)

Instead, change to:

const db_location = {
  getLocations: function() {
    return fetch( ...

Also, since you're not doing anything special in the getLocations catch block, you might consider omitting it entirely and let the caller handle it.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Many thanks for your answer! I have a further question. Please refer to EDIT 1 as above. – alextc Jul 19 '18 at 01:39
  • Your `EDIT 1` doesn't look to be `return`ing the initial `fetch`, which is exactly what you need to to to chain the promises together, as said in the answer...? – CertainPerformance Jul 19 '18 at 01:45
  • Does it have to return the initial fetch? Is there a way to return the response.json() from the fetch to the route function? response.json() from the fetch call is a Promise accordin to node-fetch documentation. – alextc Jul 19 '18 at 01:47
  • Yes, you need to both return the `res1.json()` from the `.then` chained right after the `fetch` *in addition to returning the `fetch` itself*, that way the consumer of `getLocations` can see and chain onto the end of the returned Promise chain. `return fetch` – CertainPerformance Jul 19 '18 at 01:49
  • Did you mean return both res1.json() and fetch from the getLocations() function? Can you please show an example? – alextc Jul 19 '18 at 01:58
  • eg `getLocations: () => fetch( ... ).then(res1 => res1.json())` using arrow functions' implicit return – CertainPerformance Jul 19 '18 at 02:00
0

Your function doesn't return anything.

If you want to use a promise, you need return it.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Many thanks! I have made some changes to the code and it returned a Promise object but the same error was thrown. Please refer to EDIT as above. – alextc Jul 19 '18 at 01:41