简体   繁体   中英

Axios requests with express, node, ejs

I am working on a site using Express.js, node.js, Axios, and ejs. I am making REST calls to a Oracle SQL REST services using Axios. I am having trouble working with Promises or Async/Await. I could use some guidance, if possible.

I have a repository layer to interface with the Oracle DB. For example:

dataaccess.js

const axios = require('axios');

exports.IsManufacturerCategory = function (categoryId) {
    axios.get(`DB ADDRESS ${categoryId}`)
        .then(response => {
            console.error('GET IsManufacturerCategory categoryId = ' + categoryId);
            console.error('Response = ' + JSON.stringify(response.data));

            return (response.data);
        })
        .catch(rej => {
            console.error('ERROR IsManufacturerCategory categoryId = ' + categoryId);
            console.error('ERR = \n' + rej.data);
            return (rej.data);
        });
}

Which is called in my middleware. When I call var isManufacturerCat = exports.IsManufacturerCategory(categoryId); it is undefined. I am attempting to use the data retrieved from the Axios call to return a ejs view to my router, which I can provide if needed.

category.js

var isManufacturerCat = exports.IsManufacturerCategory(categoryId);
if (isManufacturerCat) {
    var models = dataaccess.GetCategorySubCategories(categoryId);
    return ("manufacturers", {
        data: {
            Canonical: cononical, 
            Category: category, 
            IsAManufacturerCategory: iAManufacturerCat, 
            Models: models
        }
    });
}

I am open to any advice in my project structure, usage of Promises, Async/Await, etc.

Thank you in advance.

EDIT

After working with some of the answers given, I have made some progress but I am having issues with layers of async calls. I end up getting into a spot where I need to await a call, but I am in a function that I am not able/do not want to do so (ie my router).

indexMiddleware.js

exports.getRedirectURL = async function (fullOrigionalpath) {

    if (fullOrigionalpath.split('.').length == 1 || fullOrigionalpath.indexOf(".aspx") != -1) {
        if (fullOrigionalpath.indexOf(".aspx") != -1) { 
            //some string stuff to get url

        }
        else if (fullOrigionalpath.indexOf("/solutions/") != -1) {
            if (!fullOrigionalpath.match("/solutions/$")) {
                if (fullOrigionalpath.indexOf("/t-") != -1) {
                    //some stuff
                }
                else {
                    var solPart = fullOrigionalpath.split("/solutions/");
                    solPart = solPart.filter(function (e) { return e });

                    if (solPart.length > 0) {
                        var solParts = solPart[solPart.length - 1].split("/");
                        solParts = solParts.filter(function (e) { return e });
                        if (solParts.length == 1) {
                            waitForRespose = true;

                            const isASolutionCategory = await dataaccess.isASolutionCategory(solParts[0]); // returns void

                            if (isASolutionCategory != undefined && isASolutionCategory.length > 0 && isASolutionCategory[0].Count == 1) {
                                 // set redirecturl   
                            }
                        }
                        else {
                            redirecturl = "/solutions/solutiontemplate";
                        }
                    }
                }
            }
        }
        else if (URL STUFF) {
            // finally if none of the above fit into url condition then verify current url with Category URL or product url into database and if that matches then redirect to proper internal URL
            if (fullOrigionalpath.lastIndexOf('/') == (fullOrigionalpath.length - 1)) {
                fullOrigionalpath = fullOrigionalpath.substring(0, fullOrigionalpath.lastIndexOf('/'));
            }

            waitForRespose = true;

            const originalURL = await exports.getOriginalUrl(fullOrigionalpath); //returns string
            redirecturl = originalURL;
            return redirecturl;
        }
    }

    if (!waitForRespose) {
        return redirecturl; 
    }
}

exports.getOriginalUrl = async function (friendlyUrl) {
    var originalUrl = '';
    var urlParts = friendlyUrl.split('/');
    urlParts = urlParts.filter(function (e) { return e });
    if (urlParts.length > 0) {
        var skuID = urlParts[urlParts.length - 1];

        const parts = await dataaccess.getFriendlyUrlParts(skuID); //returns void
        console.log("Inside GetOriginalUrl (index.js middleware) FriendlyUrlParts: " + parts);//undefined

        if (parts != undefined && parts != null && parts.length > 0) {
            //some stuff
        }
        else {
            // verify whether it's category URL then return the category local URL
            console.log('Getting CategoryLocalUrl');
            const categoryLocalUrl = await dataaccess.getCategoryLocalUrl(friendlyUrl); // returns void
            console.log('CategoryLocalUrl Gotten ' + JSON.stringify(categoryLocalUrl)); //undefined
            if (categoryLocalUrl != undefined && categoryLocalUrl.length > 0) {
                //set originalUrl
                return originalUrl;
            }

        }
    }
    else { return ''; }
}

index.js router

router.use(function (req, res, next) {
   //bunch of stuff
   index.getRedirectURL(url)
      .then(res => {
        req.url = res;
      })
      .catch(error => {
        console.error(error);
      })
      .finally(final => {
        next();
      });
}

I am getting undefined in my console.log s after the await s. I'm not really sure what I'm doing I guess.

Let's start with dataaccess.js. Basically, you're exporting a function that's doing async work, but the function isn't async. Most people want to be able to utilize async/await, so rather than have IsManufacturerCategory accept a callback function, it would better to have the function return a promise. The easiest way to do that is to make the function an async function. Async functions return promises which are resolved/rejected more easily than by returning an explicit promise. Here's how that could be rewritten:

const axios = require('axios');

exports.IsManufacturerCategory = async function (categoryId) {
  try {
    const response = await axios.get(`DB ADDRESS ${categoryId}`);

    console.log('GET IsManufacturerCategory categoryId = ' + categoryId);
    console.log('Response = ' + JSON.stringify(response.data));
  } catch (err) {
    console.error('ERROR IsManufacturerCategory categoryId = ' + categoryId);
    console.error('ERR = \n' + rej.data);

    throw err;
  }
}

Note that I'm using console.error only for errors. Because you wanted to log some error related details, I used a try/catch statement. If you didn't care about doing that, the function could be simplified to this:

const axios = require('axios');

exports.IsManufacturerCategory = async function (categoryId) {
    const response = await axios.get(`DB ADDRESS ${categoryId}`);

    console.log('GET IsManufacturerCategory categoryId = ' + categoryId);
    console.log('Response = ' + JSON.stringify(response.data));
}

This is because async functions automatically swallow errors and treat them as rejections - so the promise returned by IsManufacturerCategory would be rejected. Similarly, when an async function returns a value, the promise is resolved with the value returned.

Moving on to category.js... This looks strange because you're accessing IsManufacturerCategory from the exports of that module when I think you mean to access it from the import of the dataaccess module, right?

Inside this function, you should put any async work in an async function so that you can use await with function that return promises. Here's how it could be rewritten:

const dataaccess = require('dataccess.js');

async function validateManufacturerCat(categoryId) {
  const isManufacturerCat = await dataaccess.IsManufacturerCategory(categoryId);

  if (isManufacturerCat) {
    const models = await dataaccess.GetCategorySubCategories(categoryId);

    return ({
      manufacturers: {
        data: {
          Canonical: cononical, 
          Category: category, 
          IsAManufacturerCategory: iAManufacturerCat, 
          Models: models
        }
      }
    });
  }
}

validateManufacturerCat(categoryId)
  .then(res => {
    console.log(res);
  })
  .catch(err => {
    console.error(err);
  });

A couple notes:

  1. I changed the return value in the if statement to be a single value. You should try to always return a single value when working with promises and async/await (since you can only resolve/return one value).
  2. I see lots of functions starting with capital letters. There's a convention in JavaScript where functions with capital letters are constructor functions (meant to be invoked with the new keyword).

Here is a working example. Note that you need a callback function to get the data when it is available from the promise

//client.js
const axios = require("axios")


    exports.IsManufacturerCategory = function (url, callback) { 
       axios.get(url)
         .then(response=>
            {
                 callback(response.data);
            })
            .catch(error=>{
                callback( error);
            })
    };


    //app.js
   const client = require('./client');

    function process(data) {

        console.log(data)
    }    
     client.IsManufacturerCategory("http://localhost:3000/persons",process);

documentation

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM