Appearance
useApi & useOrgApi
Reactive composables for API calls in component setup. Wrappers around Nuxt's useFetch with type safety.
When to Use
- ✅ Loading data on component mount
- ✅ Data that needs to be reactive in the template
- ✅ Organization-specific data (use
useOrgApi) - ❌ Form submissions (use
$apiFetchinstead) - ❌ Event handlers (use
$apiFetchinstead)
Basic Usage
vue
<script setup>
// General API call
const { data, pending, error } = useApi('/api/v1/auth/me', {
lazy: true // ← Always use this for better UX
})
// Organization-scoped (auto-refreshes when user switches org)
const { data: settings } = useOrgApi('/api/organizations/settings', {
lazy: true
})
</script>
<template>
<div v-if="pending">Loading...</div>
<div v-else-if="error">{{ error.message }}</div>
<div v-else>{{ data }}</div>
</template>Type Safety
All paths, query params, and responses are fully typed from OpenAPI:
typescript
// ✅ Full autocomplete and type checking
const { data } = useApi('/api/v1/auth/me', {
query: { ... } // TypeScript validates these
})
// data.value is typed - you get autocomplete
console.log(data.value?.name)useOrgApi Special Behavior
The key difference: useOrgApi concatenates the organization ID into the cache key.
typescript
// When user switches from org123 → org456:
const { data } = useOrgApi('/api/organizations/settings')
// ✅ Automatically refetches for new org
// ✅ No manual refresh neededWhen to use useOrgApi:
- Almost everything under
/hr/:orgIdroutes - Organization settings, employees, payroll, time-off, etc.
- Any data that should refresh when user switches organizations
Common Patterns
Pagination
vue
<script setup>
const page = ref(1)
const { data } = useOrgApi('/api/organizations/employees', {
query: computed(() => ({ page: page.value, pageSize: 10 })),
lazy: true
})
</script>Reactive Path Parameters
vue
<script setup>
const employeeId = ref(123)
// Use a function for reactive paths
const { data } = useApi(
() => `/api/organizations/employees/${employeeId.value}`,
{ lazy: true }
)
</script>Manual Refresh
vue
<script setup>
const { data, refresh } = useOrgApi('/api/organizations/employees', {
lazy: true
})
const handleRefresh = () => refresh()
</script>Dependent Requests
vue
<script setup>
const { data: user } = useApi('/api/v1/auth/me', { lazy: true })
const { data: settings } = useApi(
() => `/api/users/${user.value?.id}/settings`,
{
lazy: true,
immediate: computed(() => !!user.value?.id)
}
)
</script>Key Options
typescript
useApi('/api/endpoint', {
lazy: true, // ← Use this! Don't block page load
query: { ... }, // Query params
immediate: false, // Don't execute until execute() called
watch: [someRef], // Refetch when these change
})Only for GET Requests
useApi/useOrgApi are designed for fetching data (GET requests). For POST/PUT/DELETE operations, use $apiFetch instead.
Best Practices
Do's ✅
- Always use
lazy: truefor better UX - Use
useOrgApifor organization data - Use computed for reactive queries
- Handle loading and error states
Don'ts ❌
- Don't use for form submissions → use
$apiFetch - Don't use
useFetchdirectly → use our wrappers - Don't forget
lazy: true
Error Handling
Errors are automatically typed, no type guard needed:
vue
<script setup>
const { data, error } = useOrgApi('/api/organizations/employees/123')
// error.value is fully typed
if (error.value?.statusCode === 404) {
// Handle not found
}
</script>404 Navigation Pattern
Important: On detail routes (/resource/id/*), always navigate back on 404:
vue
<script setup>
const route = useRoute('hr-orgId-employees-module-id')
const employeeId = computed(() => route.params.id)
const { data, error } = useOrgApi(`/api/organizations/employees/${employeeId.value}`)
// Navigate back to list on 404 (org switch, deleted resource, etc.)
watch(error, (err) => {
if (err?.statusCode === 404) {
navigateTo({ name: 'hr-orgId-employees-module', params: { module: route.params.module } })
}
})
</script>Why? 404s on detail routes typically happen when users switch orgs or return to old bookmarks. Navigating back provides better UX than an error page.
See Error Handling → for complete patterns.
Next: Learn $apiFetch → | Back to Overview → | Error Handling →