2
\$\begingroup\$

I have built a simple Nuxt 3 app and have some custom api endpoints.

I am currently tracking the user query and response statuses to have some insight when something goes wrong and that the app is working as expected.

Running steps

  1. User will call the endpoint api/search with query parameters
  2. Endpoint will set up the process
  3. Call a third-party api from the server
  4. If the response is ok, the data will be transformed and returned.
  5. in case of error, an error message (and status code) will be returned to the user
  6. Tracking of the user's status code and search query.

Code (simplified)

// api/search.js
const URL = '...'
const buildDataset = items => items.map(...)

// STEP 1: client calls endpoint
export default defineEventHandler(async (event) => {
  // STEP 2: setup
  const param = useQuery(event)
  const query = param.query
  const URL = '...'
  const res = {
    items: [],
    status: null,
    msg: ''
  }
  // STEP 3: get data
  try {
    const response = await fetch(URL, {
      headers: {
        mode: 'cors',
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'application/json'
      }
    })
    if (!response.ok) {
      // will this be executed if anything goes wrong? is step 5 here?
      res.status = response.status
      res.msg = response.statusText
      return res
    }
    // STEP 4: transform and return data
    const results = await response.json()
    res.status = response.status
    res.items = buildDataset(results.collection)
    return res
  // STEP 5: handle error
  } catch (err) {
    // res.status = err.response.status // do I got a validate status code here?
    res.msg = 'An error occurred'
    return res
  // STEP 6: track status code and user search query
  } finally {
    const data = { query, status: res.status }
    fetch(SUPABASE_URL, {
      method: 'POST',
      headers: {
        'apikey': SUPABASE_KEY,
        'Authorization': 'Bearer ' + SUPABASE_KEY,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    })
  }
})

Questions

  1. Am I mixing some concepts with my !response.ok? I feel like the line don't get triggered if there is an error getting the data.
  2. Will my data be returned to the client immediately when the data arrives, and will my finally be executed at the end? or will this block the return of the data?
  3. Where can I set the error status in my code to notify the user and my tracking to get insight on what went wrong.
  4. Is there anything else I'm missing?
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Understanding the Fetch API

The MDN documentation on using the Fetch API answers most of your questions, it's nicely written with many example use cases, I recommend to read it well from top to bottom.

Checking that the fetch was successful

Given this code:

const response = await fetch(URL, ...)
if (!response.ok) {
  // ...
}

The if statement will not be reached if fetch throws an exception, which can happen for example when the URL is garbage, or the server does not respond, or other kind of network errors.

The documentation has a dedicated section on error handling, and recommends to use this pattern:

fetch('flowers.jpg')
  .then((response) => {
    if (!response.ok) {
      throw new Error('Network response was not OK');
    }
    return response.blob();
  })
  .then((myBlob) => {
    myImage.src = URL.createObjectURL(myBlob);
  })
  .catch((error) => {
    console.error('There has been a problem with your fetch operation:', error);
  });

Behavior of finally and the return statement

The MDN documentation on Promises explains this nicely.

The block of code in finally will always be executed, whether the return statement is reached or an exception is thrown.

For example:

const result = await new Promise(resolve => resolve("success"))
  .finally(() => console.log("finally in case of success"))

console.log("result =", result)

await new Promise((resolve, reject) => reject(new Error("failure")))
  .catch(err => console.log("failure happened"))
  .finally(() => console.log("finally in case of failure"))

await new Promise((resolve, reject) => reject(new Error("failure")))
  .finally(() => console.log("finally in case of failure without catching"))

The output of the above code will be:

finally in case of success
result = success
failure happened
finally in case of failure
finally in case of failure without catching
file:///path/to/example.js:50
await new Promise((resolve, reject) => reject(new Error("failure")))
                                              ^

Error: failure
    at file:///path/to/example.js:50:47
    at new Promise (<anonymous>)
    at file:///path/to/example.js:50:7
    at processTicksAndRejections (node:internal/process/task_queues:94:5)

Setting error status, notifying the user

Where can I set the error status in my code to notify the user and my tracking to get insight on what went wrong.

Follow the example in the MDN docs:

  • Chain the fetch to a .then(...), which checks the response.ok flag and returns response.json() if ok,
  • Chain another .then(...), which will receive the json from the previous one, handle it, and notify the user of success.
  • Chain a .catch(...) to handle exceptions that the previous calls may have thrown, for example about network errors, or when response.ok was not true. Notify the user of failure.
  • Chain a .finally(...) to do cleanup that must always be performed, regardless of successful processing of the response or failures.
\$\endgroup\$
3
  • \$\begingroup\$ Thank you for the quick response. A colleague told me not to use then() and use async/await instead. I will read the MDN article and get back to you. \$\endgroup\$ Commented Sep 7, 2022 at 10:06
  • \$\begingroup\$ Hi @wittgenstein, I don't understand the "instead" part. I think one does not exclude the other, you can use them together. It would be interesting to know the justification of your coworker, and ideally a link to documentation or more details. \$\endgroup\$
    – janos
    Commented Sep 7, 2022 at 11:02
  • \$\begingroup\$ it was like a warning not to mix the old fetch styles (then/catch) with the modern ones (try/catch) to keep my script readable. \$\endgroup\$ Commented Sep 9, 2022 at 14:45

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.