node.js - How to use the API in the same app in express.js - Stack Overflow

admin2025-04-17  2

let's say I have a REST API in express. For example this endpoint

async function getStoreController(req, res, next) {
  try {
    const { id } = req.params;
    const storeData = await Stores.getStoreById(id);

    if (!Object.keys(storeData).length) {
      return next(
        new OperationError(`There is no sotre with id ${id}`, 404, "error")
      );
    }

    res.status(200).json({
      status: "success",
      data: storeData,
    });
  } catch (err) {
    next(err);
  }
}

I want to use the same data in my view in another endpoint and when I use the previous function as a middleware or even call it then render the view an error will occur because I finished the request already. Is there a solution ? and should I make a function that only compute and return the data so if there is an REST API or web application wants this data then both of them can call the same function but the first one return JSON and the second one render a view ?

I tried a solution which is sending a fetch request to the previous endpoint and get the data then render it in my view.

Edit

async function store(req, res, next) {
  try {
    // Get the data from that endpoint
    const data = getStoreData(); // simulate calling that endpoint

    res.render("store", data);
  } catch (err) {
    next(err);
  }
}

for example that endpoint uses the same data but suppose the function must validate and some other logic so I don't wanna repeat myself

let's say I have a REST API in express. For example this endpoint

async function getStoreController(req, res, next) {
  try {
    const { id } = req.params;
    const storeData = await Stores.getStoreById(id);

    if (!Object.keys(storeData).length) {
      return next(
        new OperationError(`There is no sotre with id ${id}`, 404, "error")
      );
    }

    res.status(200).json({
      status: "success",
      data: storeData,
    });
  } catch (err) {
    next(err);
  }
}

I want to use the same data in my view in another endpoint and when I use the previous function as a middleware or even call it then render the view an error will occur because I finished the request already. Is there a solution ? and should I make a function that only compute and return the data so if there is an REST API or web application wants this data then both of them can call the same function but the first one return JSON and the second one render a view ?

I tried a solution which is sending a fetch request to the previous endpoint and get the data then render it in my view.

Edit

async function store(req, res, next) {
  try {
    // Get the data from that endpoint
    const data = getStoreData(); // simulate calling that endpoint

    res.render("store", data);
  } catch (err) {
    next(err);
  }
}

for example that endpoint uses the same data but suppose the function must validate and some other logic so I don't wanna repeat myself

Share Improve this question edited Jan 31 at 10:35 Osama Assi asked Jan 30 at 21:13 Osama AssiOsama Assi 92 bronze badges 3
  • Define a variable at higher level, so that it can be accessed by various functions – pierpy Commented Jan 30 at 21:34
  • Can you provide some pseudo code that shows what you want to do? – shotor Commented Jan 30 at 22:18
  • @shotor I added an example can you check now ? – Osama Assi Commented Jan 31 at 10:34
Add a comment  | 

1 Answer 1

Reset to default 0

I see what you're trying to do but it's probably a bit too much.

You want to go from this:

async function store(req, res, next) {
  try {
    const { id } = req.params;
    const storeData = await Stores.getStoreById(id);

    if (!storeData) {
      return next(
        new OperationError(`There is no store with id ${id}`, 404, "error")
      );
    }

    res.render("store", data);
  } catch (err) {
    next(err);
  }
}

To something like this:

const storeMiddleware = (req, res, next) => {
  const { id } = req.params
  const storeData = await Stores.getStoreById(id)

  if (!storeData) {
    return next(
      new OperationError(`There is no store with id ${id}`, 404, "error")
    );
  }

  req.store = storeData
  next()
}

app.get('/store/:id', storeMiddleware, store)
app.get('/api/store/:id', storeMiddleware, getStoreController)


async function store(req, res, next) {
  try {
    const storeData = req.storeData

    res.render("store", data);
  } catch (err) {
    next(err);
  }
}

It seems nice, we removed 6 lines of code. But we also added 4. So we really only saved 2 lines.

Also we created indirection. Looking at the store function we can't immediately see where it's getting the storeData from. We're redirected to route declaration (app.get) and then the middleware. It's not really worth it for 2 lines of code less if you ask me.

It would make more sense if you send different responses based on the Accept header:

app.get('/store/:id', (req, res, next) => {
  const { id } = req.params;
  const storeData = await Stores.getStoreById(id);

  if (!storeData) {
    return next(
      new OperationError(`There is no store with id ${id}`, 404, "error")
    );
  }

  // will check whether Accept http header contains 'application/json'
  if (req.accepts('json')) { 
    return res.status(200).json({
      status: "success",
      data: storeData,
    });    
  }

  res.render("store", data);
})

So now the user can explicitly ask your server for a JSON representation. Otherwise you render an html page.

转载请注明原文地址:http://anycun.com/QandA/1744890318a89074.html