feat: configure API dev proxy and improve useApiFetch error handling

- Add Nitro devProxy for local proxying of api/v1 and uploads to the backend server
- Improve useApiFetch to dynamically clear auth state and navigate to login on 401/403 errors
- Automatically strip Content-Type headers for multipart FormData upload request bodies
- Add css rule to fix Bootstrap Italia navbar link border display
- Add ts-expect-error tag to avoid type checking issues with bootstrap-italia bundle loading
This commit is contained in:
2026-06-12 19:04:19 +02:00 Unverified
parent 818ac15eaa
commit 834fdade2b
4 changed files with 65 additions and 3 deletions
+4
View File
@@ -1,3 +1,7 @@
a {
text-decoration: none!important;
}
html body .navbar .navbar-collapsable .navbar-nav li.nav-item a.nav-link[data-focus-mouse="true"], .navbar .navbar-collapsable .navbar-nav li.nav-item button.nav-link[data-focus-mouse="true"] {
border-color: inherit !important
}
+37 -3
View File
@@ -2,14 +2,48 @@ import { defu } from 'defu'
export const useApiFetch = <T>(request: string, options: Parameters<typeof $fetch>[1] = {}) => {
const config = useRuntimeConfig()
const token = useCookie('auth_token') // Make sure this matches the cookie name you use on login
const tokenCookie = useCookie('auth_token')
const tokenState = useState<string | null>('auth_token_state')
const tokenValue = tokenState.value ?? tokenCookie.value
const defaults: Parameters<typeof $fetch>[1] = {
baseURL: config.public.api as string,
headers: token.value ? { Authorization: `Bearer ${token.value}` } : {},
headers: tokenValue ? { Authorization: `Bearer ${tokenValue}` } : {},
}
const params = defu(options, defaults)
return $fetch<T>(request, params)
try {
if (params?.body && typeof FormData !== 'undefined' && params.body instanceof FormData) {
if (params.headers && 'Content-Type' in params.headers) {
delete params.headers['Content-Type']
}
}
} catch (e) {}
return $fetch<T>(request, params).catch((err: any) => {
const status = err?.statusCode || err?.status || err?.response?.status
if (status === 401 || status === 403) {
try {
tokenCookie.value = null
tokenState.value = null
const authUser = useState('auth_user')
authUser.value = null
console.error(`[API] Authentication error (${status}) - token cleared`)
} catch (e) {
console.error('[API] Error clearing auth state:', e)
}
try {
navigateTo('/auth/login')
} catch (e) {
console.error('[API] Error navigating to login:', e)
}
}
throw err
})
}
+1
View File
@@ -1,3 +1,4 @@
export default defineNuxtPlugin(async (nuxtApp) => {
// @ts-expect-error
await import('bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js')
})
+23
View File
@@ -20,6 +20,29 @@ export default defineNuxtConfig({
url: 'http://localhost:3000',
name: 'Visione - Un\'occhio per la sicurezza del cittadino.',
},
nitro: {
devProxy: {
'/api/v1': {
target: 'https://bk.visione.studentindipendenti.it/api/v1',
changeOrigin: true,
headers: {
host: 'bk.visione.studentindipendenti.it',
origin: 'https://visione.studentindipendenti.it',
referer: 'https://visione.studentindipendenti.it/'
}
},
'/uploads': {
target: 'https://bk.visione.studentindipendenti.it/uploads',
changeOrigin: true,
headers: {
host: 'bk.visione.studentindipendenti.it',
origin: 'https://visione.studentindipendenti.it',
referer: 'https://visione.studentindipendenti.it/'
}
}
}
},
css: [
'@/assets/css/style.css',