0

I am developing an API in javascript using node.js

What I'm trying to do is call a function which fires a chain of promises and on callback it function returns an array with information for one product.

What I want to do is to run this function as many times as required to form a list of products in JSON format.

But this list of products needs to be created before it's sent back to the user, which is where I'm struggling.

This is the function I have:

exports.findProduct = (ingredient, store, callback) => {
            products.getProductData(ingredient, store)
        .then( data => products.getProducts(data))
        .then( productList => products.filterProductData(productList))
        .then( selectedProduct => callback(null,selectedProduct))//get individual products and add to list
        .catch( err => callback(err))
}

I call it like this

products.findProduct(ingredient, 'Waitrose', (err, data) => {

    if (err) {
        //res.send(status.badRequest, {error: err.message})
    } else {
        res.send(data)
        res.end()
    }

})

The res.send(data) sends the data from the callback back to the server, but what if I want to run this function again and update an array and only then send the array to the server?

Any help of tips would be very appreciated.

1 Answer 1

1

A promise-based possible implementation that allows getAllProducts to call itself recursively.

exports.findProduct = (ingredient, store) => {
    return new Promise((resolve, reject) => {
         products.getProductData(ingredient, store)
        .then( data => products.getProducts(data))
        .then( productList => products.filterProductData(productList))
        .then( selectedProduct => resolve(selectedProduct))
        .catch( err => reject(err))
    }
}



function getAllProducts(ingredientList, shopName) {  
    const allProducts = [];
    return new Promise((resolve, reject) => {
        products.findProducts(ingredientList, shopName)
        .then(product => {
            allProducts.push(...product);

            if(/*need more products*/) {
                getAllProducts(ingredientList, 'Tesco')
                .then(newProducts => {
                    allProducts.push(...newProducts);
                    resolve(allProducts);
                })
                .catch(err => reject(err));
            } else {
                resolve(allProducts);
            }
        })
        .catch(err => reject(err));
    }
}

Called like this...

getAllProducts(ingredientList, 'Waitrose')
.then(products => {
    res.send(products);
    res.end();
}).catch(err => {
    res.send(status.badRequest, {error: err.message});
    res.end();
});

Edit:

The above approach is valid if you need to determine whether to make more call based on the result of a previous call. If you know up front that you need to make multiple calls, e.g. if you know you want to check Tesco, Waitrose and Asda, then there is a simpler way using Promise.all

exports.findProduct = (ingredient, store) => {
    return new Promise((resolve, reject) => {
         products.getProductData(ingredient, store)
        .then( data => products.getProducts(data))
        .then( productList => products.filterProductData(productList))
        .then( selectedProduct => resolve(selectedProduct))
        .catch( err => reject(err))
    }
}

function makeMultipleCalls() {  
    const stores = ['Waitrose', 'Tesco', 'Asda'];
    const promises = [];

    for (var store in stores) {
        promises.push(product.findProduct(ingredientList, store);
    }

    Promise.all(promises)
    .then(results => {
        res.send(results.reduce((a,b) => a.concat(b)));
        res.end();
    })
    .catch(err => {
        //deal with error
    });
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you so much for your answer, there's only one small issue. Inside the if statement the allProducts.push(newProducts) pushes into the same element as the first allProducts.push(newProducts). Which results in something like [product1, [product2, [product3]]]] Any ideas how to avoid this? Cheers
I've edited my answer to use the spread (...) operator so the items from newProducts get added to allProducts, rather than the array itself.
On reflection I also wondered if there was a simpler way to do this, so added a different method that may or may not be appropriate for your situation.
The for loop and promise.all solution is brilliant and very neat! I managed to implement the same idea for the products function and then the stores. Thank you, I appreciate your help very much :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.