Skip to content

useFetch Basic Usage

Learn how to use the type-safe composables generated by the CLI.

What the CLI Generates

For an OpenAPI endpoint like this:

yaml
/pet/{petId}:
  get:
    operationId: getPetById
    parameters:
      - name: petId
        in: path
        required: true
        schema:
          type: integer
    responses:
      '200':
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Pet'

The CLI generates a type-safe wrapper:

typescript
// Generated: composables/useFetchGetPetById.ts
import type { GetPetByIdRequest, Pet } from '../../..'
import { useApiRequest, type ApiRequestOptions } from '../runtime/useApiRequest'

export const useFetchGetPetById = (
  params: GetPetByIdRequest,  // ✅ Type-safe from OpenAPI
  options?: ApiRequestOptions<Pet>
) => {
  // useApiRequest returns Nuxt's useFetch under the hood
  return useApiRequest<Pet>(`/pet/${params.petId}`, {
    method: 'GET',
    ...options
  })
}

Basic Usage

Use the generated composable in your components:

vue
<script setup lang="ts">
// Type-safe composable generated by CLI
const { data: pet, pending, error } = useFetchGetPetById({ petId: 123 })
</script>

<template>
  <div v-if="pending">Loading...</div>
  <div v-else-if="error">Error: {{ error.message }}</div>
  <div v-else>
    <h1>{{ pet.name }}</h1>
    <p>Status: {{ pet.status }}</p>
  </div>
</template>

Nuxt useFetch Documentation

Generated composables wrap Nuxt's useFetch. For complete documentation on data, pending, error, refresh(), and standard options like immediate, watch, server, see:

Nuxt useFetch Official Documentation →

What the CLI Adds

1. Lifecycle Callbacks

Add hooks to intercept and react to request lifecycle events:

vue
<script setup lang="ts">
const { data: pet } = useFetchGetPetById(
  { petId: 123 },
  {
    // ⏱️ Before request
    onRequest: ({ url, headers, query }) => {
      console.log('Fetching from:', url)
      return {
        headers: {
          ...headers,
          'X-Request-ID': crypto.randomUUID()
        }
      }
    },
    
    // ✅ On success (2xx response)
    onSuccess: (pet) => {
      console.log('Loaded pet:', pet.name)
      showToast(`Welcome ${pet.name}!`, 'success')
    },
    
    // ❌ On error (4xx/5xx or network error)
    onError: (error) => {
      console.error('Failed to load pet:', error)
      if (error.status === 404) {
        showToast('Pet not found', 'error')
      }
    },
    
    // 🏁 Always runs (success or error)
    onFinish: ({ success, data, error }) => {
      console.log('Request complete:', success ? 'success' : 'failed')
    }
  }
)
</script>

Learn more about callbacks →

2. Pick

Select specific fields from the response without transform:

vue
<script setup lang="ts">
// Only get id, name, and status
const { data: pet } = useFetchGetPetById(
  { petId: 123 },
  {
    pick: ['id', 'name', 'status']
  }
)
// data is Ref<{ id: number, name: string, status: string }>
</script>

More Features

For additional features like transform, global headers, baseURL, and more, see Shared Features →

Examples with Callbacks

Simple GET Request

vue
<script setup lang="ts">
const { data: pets } = useFetchGetPets(
  {},
  {
    onSuccess: (pets) => {
      console.log(`Loaded ${pets.length} pets`)
    }
  }
)
</script>

POST Request with Success Callback

vue
<script setup lang="ts">
const form = ref({ name: '', status: 'available' })

const { execute: createPet, pending } = useFetchCreatePet(
  { body: form.value },
  {
    immediate: false, // Nuxt option: don't execute on mount
    onSuccess: (pet) => {
      showToast(`Created pet: ${pet.name}`, 'success')
      navigateTo(`/pets/${pet.id}`)
      form.value = { name: '', status: 'available' }
    },
    onError: (error) => {
      showToast(`Failed: ${error.message}`, 'error')
    }
  }
)
</script>

<template>
  <form @submit.prevent="createPet">
    <input v-model="form.name" placeholder="Pet name" />
    <button type="submit" :disabled="pending">Create</button>
  </form>
</template>

Request Interception

vue
<script setup lang="ts">
const { data: pets } = useFetchGetPets(
  {},
  {
    onRequest: ({ headers, query }) => {
      return {
        headers: {
          ...headers,
          'X-Client-Version': '1.0.0'
        },
        query: {
          ...query,
          timestamp: Date.now()
        }
      }
    }
  }
)
</script>

Error Handling with Callbacks

vue
<script setup lang="ts">
const { data: pet, error } = useFetchGetPetById(
  { petId: 123 },
  {
    onError: (error) => {
      // Handle specific error codes
      if (error.status === 404) {
        showToast('Pet not found', 'error')
        navigateTo('/pets')
      } else if (error.status === 401) {
        showToast('Please login', 'error')
        navigateTo('/login')
      } else {
        showToast('Something went wrong', 'error')
      }
    }
  }
)
</script>

Global Callback Control

The CLI also adds global callback control:

Skip Global Callbacks

vue
<script setup lang="ts">
// Skip authentication for public endpoint
const { data: publicPets } = useFetchGetPublicPets(
  {},
  {
    skipGlobalCallbacks: true // Don't apply global callbacks
  }
)
</script>

Learn more about global callbacks →

Type Safety

All parameters and responses are fully typed from your OpenAPI schema:

typescript
// ✅ Type-safe parameters
useFetchGetPetById({ petId: 123 })       // Valid
useFetchGetPetById({ petId: 'abc' })     // ❌ TypeScript error

// ✅ Type-safe response
const { data: pet } = useFetchGetPetById({ petId: 123 })
pet.value?.name      // ✅ string (autocomplete works)
pet.value?.unknown   // ❌ TypeScript error

Next Steps

Released under the Apache-2.0 License.