Home > Net >  Trying to run imported async function in API get request
Trying to run imported async function in API get request

Time:11-26

So basically I have two js-scripts; one is router, made with node and express:

import express from "express";
import showContent from "../model/model.js";

const router = express.Router();

//* Sends out the ejs (basically HTML) on start URL "localhost:8080"
router.get("/", function (req, res) {
  res.render("../pages/start.ejs");
});

//* Querys the database, the table ":id"
router.get("/:id", function (req, res, next) {
  id = req.params.id;
  let sqlQuery = `SELECT page_content FROM ${id} WHERE page_name = "about";`;
  console.log("1", showContent(sqlQuery));
  res.send(showContent(sqlQuery));

  next();
});

export default router;

and the other is a script with an async function fetching data from my SQLite db:

import sqlite3 from "sqlite3";

const db = new sqlite3.Database(
  "path/to/my/db"
);

export default function getContent(sqlQuery, whenloaded) {
  return new Promise((resolve) => {
    resolve(
      db.all(sqlQuery, [], (err, rows) => {
        if (err) {
          console.error(err);
        } else {
          rows.forEach((row) => {
            whenloaded(row.page_content);
          });
        }
      })
    );
  });
}

async function showContent(sqlQuery) {
  await getContent(sqlQuery, (result) => {
    console.log("Result:", result);
  });
}

The output in my browser is {} and the console logs I get are: 1 Promise { <pending> }, Result: "my content" and Result "my content".

I think the problem is that I genuinely don´t understand async functions, and I don´t know how to use them in my code.

CodePudding user response:

There are 3 problems with your code.

The first one, is that you are not waiting on the async function showContent to complete. That is why you receive the message of a pending Promise. I advise you to read up on Promises to understand async Javascript code better. In short: Promises are the underlying vehicle upon which async functionality is built.

To fix this problem, update your router code to wait for the showContent function before sending back the response:

router.get("/:id", async function (req, res, next) {
  const id = req.params.id;
  const sqlQuery = `SELECT page_content FROM ${id} WHERE page_name = "about";`;
  const content = await showContent(sqlQuery);
  console.log("1", content);
  res.send(content);

  next();
});

The second problem is that you are exporting a default function and a showContent function from your model file. However, you use the import statement:

import showContent from "../model/model.js";

Which imports the default export of the model.js file, in your case the getContent function, and assigns it to the local variable showContent. My assumption is that you actually wanted the showContent function, so you should update the import statement to (notice the curly braces):

import { showContent } from "../model/model.js";

The third problem is with the async code in your model file. Firstly, the showContent function does not return anything. Hence, waiting for the result will yield undefined. Secondly, you should restructure the getContent function so you do not need the whenLoaded callback by employing the power of Promises correctly. Update the model code to:

import sqlite3 from "sqlite3";

const db = new sqlite3.Database(
  "path/to/my/db"
);

export function showContent(sqlQuery) {
  return new Promise((resolve, reject) => {
      db.all(sqlQuery, [], (err, rows) => {
        if (err) {
          reject(err);
        } else {
          resolve(rows);
        }
      });
  });
}

I've removed the now redundant showContent function and renamed the getContent function to showContent so your previously updated import statement still works. You can of course always update the naming and reintroduce the default export (but remember to remove the curly braces from the import statement if you do).

  • Related