Raw Responses
Access full HTTP response details including status codes, headers, and raw data using the Raw variant of generated composables.
Overview
Every useAsyncData composable has a Raw variant that returns the complete response object:
// Standard variant - returns data only
const { data: pets } = useAsyncDataGetPets()
// Raw variant - returns full response with headers and status
const { data: response } = useAsyncDataGetPetsRaw()CLI Addition - Not in Nuxt
Important: Nuxt's native useAsyncData does NOT return response headers or status codes.
Our CLI's Raw variant adds this capability, giving you access to:
- ✅
headers- Full Headers object - ✅
status- HTTP status code (200, 404, etc.) - ✅
statusText- Status message ("OK", "Not Found", etc.) - ✅
data- Response data (just like standard variant)
This is especially useful for:
- Pagination information in headers
- Rate limiting headers
- ETags for caching
- Custom API metadata
Generated Raw Composables
For each operation, two composables are generated:
// Standard - returns only data
export function useAsyncDataGetPets(
params?: {},
options?: ApiAsyncDataOptions<Pet[]>,
customKey?: string
) {
return useApiAsyncData<Pet[]>('/pets', { method: 'GET', ...options }, customKey)
}
// Raw (adds "Raw" suffix) - returns full response
export function useAsyncDataGetPetsRaw(
params?: {},
options?: ApiAsyncDataOptions<RawResponse<Pet[]>>,
customKey?: string
) {
return useApiAsyncDataRaw<Pet[]>('/pets', { method: 'GET', ...options }, customKey)
}By default, keys are auto-generated from operation + resolved URL + params.
useAsyncDataGetPetById-/pet/1useAsyncDataGetPetById-/pet/2useAsyncDataFindPetsByStatus-/pet/findByStatus-{"status":"available"}useAsyncDataGetInventory-/store/inventory
You can override with a custom key if you want intentional cache sharing:
const { data: response } = useAsyncDataFindPetsByStatusRaw(
{ status: 'available' },
undefined,
'mi-clave'
)Response Structure
Raw responses have this structure:
interface RawResponse<T> {
status: number // HTTP status code (200, 404, etc.)
statusText: string // Status text ("OK", "Not Found", etc.)
headers: Headers // Response headers
data: T // Actual response data
}Basic Usage
Accessing Status Code
<script setup lang="ts">
const { data: response } = useAsyncDataGetPetsRaw()
watch(response, (res) => {
if (res) {
console.log('Status:', res.status) // 200, 404, 500, etc.
if (res.status === 200) {
console.log('Success!')
} else if (res.status === 404) {
console.log('Not found')
}
}
})
</script>
<template>
<div>
<p>HTTP Status: {{ response?.status }}</p>
<ul>
<li v-for="pet in response?.data" :key="pet.id">
{{ pet.name }}
</li>
</ul>
</div>
</template>Accessing Headers
<script setup lang="ts">
const { data: response } = useAsyncDataGetPetsRaw()
const rateLimit = computed(() => {
if (!response.value) return null
return {
limit: response.value.headers.get('X-RateLimit-Limit'),
remaining: response.value.headers.get('X-RateLimit-Remaining'),
reset: response.value.headers.get('X-RateLimit-Reset')
}
})
</script>
<template>
<div>
<p v-if="rateLimit">
Rate Limit: {{ rateLimit.remaining }} / {{ rateLimit.limit }}
</p>
<ul>
<li v-for="pet in response?.data" :key="pet.id">
{{ pet.name }}
</li>
</ul>
</div>
</template>Common Use Cases
Pagination Headers
Many APIs return pagination info in headers:
<script setup lang="ts">
const page = ref(1)
const { data: response, refresh } = useAsyncDataGetPetsRaw(
{ page: page.value }
)
const pagination = computed(() => {
if (!response.value) return null
return {
total: Number(response.value.headers.get('X-Total-Count')),
page: Number(response.value.headers.get('X-Page')),
perPage: Number(response.value.headers.get('X-Per-Page')),
totalPages: Number(response.value.headers.get('X-Total-Pages'))
}
})
const nextPage = () => {
page.value++
refresh()
}
const prevPage = () => {
if (page.value > 1) {
page.value--
refresh()
}
}
</script>
<template>
<div>
<ul>
<li v-for="pet in response?.data" :key="pet.id">
{{ pet.name }}
</li>
</ul>
<div v-if="pagination" class="pagination">
<button @click="prevPage" :disabled="page === 1">Previous</button>
<span>Page {{ pagination.page }} of {{ pagination.totalPages }}</span>
<button @click="nextPage" :disabled="page >= pagination.totalPages">
Next
</button>
</div>
</div>
</template>ETags for Caching
<script setup lang="ts">
const etag = ref<string | null>(null)
const { data: response, refresh } = useAsyncDataGetPetsRaw(
{},
{
onRequest: ({ headers }) => {
// Send If-None-Match if we have an ETag
if (etag.value) {
headers['If-None-Match'] = etag.value
}
}
}
)
watch(response, (res) => {
if (res) {
// Store new ETag
const newEtag = res.headers.get('ETag')
if (newEtag) {
etag.value = newEtag
}
// Check if cached (304 status)
if (res.status === 304) {
console.log('Using cached data')
}
}
})
</script>Rate Limiting
<script setup lang="ts">
const { data: response } = useAsyncDataGetPetsRaw()
const rateLimitStatus = computed(() => {
if (!response.value) return null
const remaining = Number(response.value.headers.get('X-RateLimit-Remaining'))
const limit = Number(response.value.headers.get('X-RateLimit-Limit'))
const resetTime = Number(response.value.headers.get('X-RateLimit-Reset'))
return {
remaining,
limit,
percentage: (remaining / limit) * 100,
resetsAt: new Date(resetTime * 1000)
}
})
// Show warning when approaching limit
watch(rateLimitStatus, (status) => {
if (status && status.percentage < 10) {
showToast(`Rate limit warning: ${status.remaining} requests remaining`, 'warning')
}
})
</script>
<template>
<div>
<div v-if="rateLimitStatus" class="rate-limit-indicator">
<div
class="bar"
:style="{ width: rateLimitStatus.percentage + '%' }"
/>
<span>{{ rateLimitStatus.remaining }} / {{ rateLimitStatus.limit }}</span>
</div>
<ul>
<li v-for="pet in response?.data" :key="pet.id">
{{ pet.name }}
</li>
</ul>
</div>
</template>Custom Status Handling
<script setup lang="ts">
const { data: response } = useAsyncDataGetPetByIdRaw(
{ petId: 123 }
)
const message = computed(() => {
if (!response.value) return 'Loading...'
switch (response.value.status) {
case 200:
return `Pet found: ${response.value.data.name}`
case 404:
return 'Pet not found'
case 403:
return 'You do not have permission to view this pet'
case 500:
return 'Server error, please try again'
default:
return `Unexpected status: ${response.value.status}`
}
})
</script>
<template>
<div>
<p>{{ message }}</p>
<div v-if="response?.status === 200">
<h1>{{ response.data.name }}</h1>
<p>Status: {{ response.data.status }}</p>
</div>
</div>
</template>Content Type Detection
<script setup lang="ts">
const { data: response } = useAsyncDataGetPetImageRaw()
const contentType = computed(() => {
return response.value?.headers.get('Content-Type')
})
const isImage = computed(() => {
return contentType.value?.startsWith('image/')
})
const isJson = computed(() => {
return contentType.value?.includes('application/json')
})
</script>
<template>
<div>
<p>Content-Type: {{ contentType }}</p>
<img v-if="isImage" :src="response?.data" />
<pre v-else-if="isJson">{{ response?.data }}</pre>
</div>
</template>Combining with Standard Variant
You can use both variants when needed:
<script setup lang="ts">
// For display (simple)
const { data: pets } = useAsyncDataGetPets()
// For metadata (detailed)
const { data: response } = useAsyncDataGetPetsRaw()
const totalCount = computed(() => {
return response.value?.headers.get('X-Total-Count')
})
</script>
<template>
<div>
<p>Total: {{ totalCount }}</p>
<ul>
<li v-for="pet in pets" :key="pet.id">{{ pet.name }}</li>
</ul>
</div>
</template>TypeScript Support
Raw responses are fully typed:
const { data: response } = useAsyncDataGetPetsRaw()
// TypeScript knows the structure
response.value?.status // number
response.value?.statusText // string
response.value?.headers // Headers
response.value?.data // Pet[] (typed from OpenAPI)When to Use Raw Responses
✅ Use Raw When:
- Need to read response headers
- Need HTTP status codes
- Working with pagination headers
- Implementing ETags/caching
- Need rate limit information
- Custom status code handling
❌ Use Standard When:
- Only need response data
- Don't care about headers/status
- Simpler code is preferred
- Type transformations are needed
