-1

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

3
  • Define a variable at higher level, so that it can be accessed by various functions Commented Jan 30 at 21:34
  • Can you provide some pseudo code that shows what you want to do? Commented Jan 30 at 22:18
  • @shotor I added an example can you check now ? Commented Jan 31 at 10:34

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I mean yeah in this case you are totally correct there is no need to do this to only save 2 lines of code but my point is: if there is an API and we want to develop a mobile application and a web application so in web application we want to use the API so it shouldn't do the stuff you've provided ? so it's totally fine to send a fetch request to the API right ? even in example of REST API my question is somehow wrong because if we are using a REST API then SPA will be our web application right ?
If you're doing an SPA. Then you wouldn't use render like this. You would have a single route to your SPA (for instance, anything that doesn't start with /api) and your SPA would do fetch requests to the REST API to get JSON data and do something with it. Your mobile application would also do fetch requests to the API to get its data. res.render() is only used if you're building a server rendered web application. So all the HTML gets rendered on the server, and only HTML is sent to the browser. If you click on a link, you get full browser refresh

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.