1

I'm writing a service that makes an API call to get all bookings, then from those bookings gets a list all the coworkerIds who made those bookings. I then take the unique ids and use them to make another set of calls, to get an array of all the coworker records. Once this step is done I'll do the same for line item calls, however for some reason I can't get my list of coworker objects.

Here's my code:

apiService.getBookingsList(`?size=1000&from_Booking_FromTime=${weekAgo.toISOString()}`).then(bookings => {
    const bookingCoworkerIds = bookings.map(booking => booking.CoworkerId);
    const bookingCoworkerIdsUnique = bookingCoworkerIds.filter(recordParser.onlyUnique);

    const getCoworker = function getCoworkerInfo(coworkerId)  {
        return apiService.getSingleCoworker(coworkerId);
    }

    const bookingCoworkerCalls = bookingCoworkerIdsUnique.map(coworkerId => getCoworker(coworkerId));
    const bookingCoworkers = Promise.all(bookingCoworkerCalls);

    bookingCoworkers.then(coworkers => {
       console.log(coworkers.length);
       console.log(coworkers[0]);
    });
});

And here's the code for apiService.getSingleCoworker:

getSingleCoworker(coworkerId) {
    // returns a single coworker object given their ID
    return httpsRequest.createRequest(this.URL.coworkerList + `?Coworker_Id=${coworkerId}`, {}, this.requestHeaders, 'GET')
        .then(result => JSON.parse(result).Records[0]);
}

I can also post my https code but I don't think that's the issue.

I suspect I'm doing something wrong with my promise pattern, as I'm still new to promises and async code in general. Neither of these console logs are reached, and instead the only output is:

(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): SyntaxError: Unexpected end of JSON input

So what am I doing wrong here?

no_parachute44
  • 365
  • 1
  • 15
  • `SyntaxError: Unexpected end of JSON input` you verify the JSON is correct? Looks like it's not catching the error properly. – escapesequence Aug 14 '18 at 15:45
  • `SyntaxError: Unexpected end of JSON input` means that (at least one of) your `result` is not a valid JSON string. Try logging them before attempting to parse. Fix `createRequest` or your server code accordingly then. – Bergi Aug 14 '18 at 15:45
  • Is there a quick way to modify getSingleCoworker() to retry if the returned response is invalid? – no_parachute44 Aug 14 '18 at 15:50

1 Answers1

0

The idea of working with promises is chaining "then" calls (or commands).

In order to do that, a promise must return another promise or a value.

Like this:

apiService.getBookingsList(`?size=1000&from_Booking_FromTime=${weekAgo.toISOString()}`)
    .then(bookings => {
        const bookingCoworkerIds = bookings.map(booking => booking.CoworkerId);
        const bookingCoworkerIdsUnique = bookingCoworkerIds.filter(recordParser.onlyUnique);

        const bookingPromises = bookingCoworkerIdsUnique.map(coworkerId => apiService.getSingleCoworker(coworkerId));
        return Promise.all(bookingPromises);

    }).then(coworkers => {
       console.log(coworkers.length);
       console.log(coworkers[0]);
    }).catch(err => {
        // do something with error
    });

inside the first "then" callback I return Promise.all which generates a promise.

The next "then" receives all the resolved values by the "all" promise.

Bear in mind that promises should always contain a "catch" call at the end in order to capture promise errors.

EDIT:

getSingleCoworker(coworkerId) {
    const self = this;
    return new Promise(function(resolve, reject) {
        httpsRequest.createRequest(self.URL.coworkerList + `?Coworker_Id=${coworkerId}`, {}, this.requestHeaders, 'GET')
            .then(result => {
                const jsonVal = JSON.parse(result).Records[0];
                resolve(jsonVal);
            }).catch(reject);
    });
}

Hope this helps

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Martín Zaragoza
  • 1,717
  • 8
  • 19
  • 1
    His code may work if modified to catch the error properly, but I'd recommend this approach with chaining `then` and `catch` – escapesequence Aug 14 '18 at 15:48
  • I ran your code but am doing something wrong still, I get the same error – no_parachute44 Aug 14 '18 at 15:49
  • 1
    It's most likely your JSON data stream my dude, have you debugged/viewed what JSON information your given? – escapesequence Aug 14 '18 at 15:49
  • Yeah I've made the calls for getting coworkers via Postman and the response looked fine, did the same for a single call with an ID I knew with getSingleCoworker() and got a good response back. Is there something else I should try? – no_parachute44 Aug 14 '18 at 15:51
  • Now getting (node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 104): TypeError: Cannot read property 'URL' of undefined Also, httpsRequest.createRequest already returns a promise, is it a good idea to nest them? – no_parachute44 Aug 14 '18 at 16:00
  • No problem chaining promises as long as u call resolve and reject properly. I've updated my answer once again... forgot to handle "this" properly (when asking for URL field value). You can use self = this or you can use lambdas and avoid creating a self variable – Martín Zaragoza Aug 14 '18 at 16:04
  • Check the updated `getSingleCoworker(coworkerId)` function. – Martín Zaragoza Aug 14 '18 at 16:11
  • Still getting SyntaxError: Unexpected end of JSON input at Object.parse (native) So it looks like sometimes the API responds with an empty response, and I have no idea why. I haven't been able to replicate this behavior in Postman and am not sure what's causing it or what to do about it. I'm working on using setTimeout getCoworker = function getCoworkerInfo portion to put a delay between each call in case the API rejects too many calls at once. Any chance you know how to do this off hand? – no_parachute44 Aug 14 '18 at 16:14
  • well you should handle empty body responses in the then clause and do something or call reject – Martín Zaragoza Aug 14 '18 at 16:17
  • (edited my previous comment) tried this but I get a timeout object instead of a record: const getCoworker = function getCoworkerInfo(coworkerId) { //return apiService.getSingleCoworker(coworkerId); return setTimeout(function(){ return apiService.getSingleCoworker(coworkerId); }, 10); } – no_parachute44 Aug 14 '18 at 16:23
  • Went ahead and marked this as the right answer, though if you think of how to resolve my previous question please let me know!! – no_parachute44 Aug 14 '18 at 17:04
  • Great this `getCoworker` function is used for testing? Are you trying to simulate async calls ? who calls it? – Martín Zaragoza Aug 14 '18 at 17:18
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it) in the code of your EDIT! – Bergi Aug 14 '18 at 20:59