Search code examples
vuejs3fetch-apinuxt3.js

Nuxt3 catching errors when calling a remote api via server/api/someCall


In my first Nuxt3 app I'm trying to setup my external API requests within the server/api folder.

With the configuration below, on a successful request everything is great. However, I am struggling to determine how to get the error response back out.

My <TestApi></TestApi> File:

<template>
  <div>
    <div>Check developer console!</div>
  </div>
</template>

<script setup>

onMounted(async () => {
  const company = await $fetch('/api/getCompany', {
    async onRequestError({ request, options, error }) {
      // Log error
      console.log('[fetch request error]', request, error)
    }
  })


  console.log(company)
})

// const config = useRuntimeConfig()
// console.log('Runtime config:', config.apiBase)
// if (process.server) {
//   console.log('API secret:', config.apiSecret)
// }
</script>

My server/api/getCompany.ts file:

export default defineEventHandler(async (event) => {
  //Defined in nuxt.config.ts
  const config = useRuntimeConfig()
  const baseURL = config.public.apiBase

  const company = await $fetch(baseURL+'/company?bookingAppApiKey='+config.apiSecret, {
    async onRequestError({ request, options, error }) {
      // Log error
      console.log('[fetch request error]', request, error)
    }
  })

  return company
})

I would like to get the remote URL request response code and message out of /server/api/getCompany.ts for handling in <TestApi>.


Solution

  • $fetch will throw an error and based on that you can customize your error message returned by the server route and add arbitrary information:

    // ~/server/api/getCompany.ts
    
    import { FetchError } from 'ohmyfetch'
    
    export default defineEventHandler(async () => {
      const url = 'https://google.com/404' // or: baseURL+'/company?bookingAppApiKey='+config.apiSecret
    
      try {
        return await $fetch(url)
      } catch (err) {
        throw createError({
          statusCode: 444,
          message: 'Oh no!',
          data: {
            statusCode: (err as FetchError).response?.status,
            responseBody: (err as FetchError).data,
          },
        })
      }
    })
    
    

    (The type handling can apparently be improved in my answer.)

    Similarly you can catch the error in your component and handle it to your need.

    Please think twice, whether if you really want to expose information from the server response. This can potentially contain confidential data, e.g. your API secret. In general it is better, to log this on the server side, but not expose this publicly in your API response.