Composables
useCrudResource
Risorsa CRUD generica con stato items/loading/error e operazioni load/create/update/delete tipizzate.
Signature
function useCrudResource<
T extends Identifiable,
CreateRequest,
UpdateRequest = Partial<CreateRequest>,
>(
options: CrudResourceOptions<T, CreateRequest, UpdateRequest>,
): CrudResourceResult<T, CreateRequest, UpdateRequest>
Astrae il pattern ricorrente useRoles/usePermessi/useTag/ecc. in un composable generico, mantenendo i tre type parameter per evitare collassi a any.
Type parameters
| Parameter | Vincolo | Descrizione |
|---|---|---|
T | extends Identifiable (= { id: string }) | Entità della risorsa (deve avere id: string) |
CreateRequest | — | Payload per la create (es. Omit<T, 'id'>) |
UpdateRequest | default Partial<CreateRequest> | Payload per l'update; di default è parziale della create |
Opzioni CrudResourceOptions
interface CrudResourceOptions<T extends Identifiable, CreateRequest, UpdateRequest = Partial<CreateRequest>> {
loadItems: (filters?: Record<string, unknown>) => Promise<T[]>
createItem: (payload: CreateRequest) => Promise<T>
updateItem?: (id: string, payload: UpdateRequest) => Promise<T>
deleteItem?: (id: string) => Promise<void>
resourceName: string
autoReload?: boolean
}
| Opzione | Tipo | Default | Descrizione |
|---|---|---|---|
loadItems | (filters?) => Promise<T[]> | — | Obbligatorio. Fetcher principale. Riceve filtri opzionali, ritorna lista |
createItem | (payload) => Promise<T> | — | Obbligatorio. Crea un nuovo elemento |
updateItem | (id, payload) => Promise<T> | — | Update (opzionale). Senza questo, result.update non è esposto |
deleteItem | (id) => Promise<void> | — | Delete (opzionale). Senza questo, result.delete non è esposto |
resourceName | string | — | Obbligatorio. Usato nei messaggi di errore (Errore caricamento ${resourceName}) |
autoReload | boolean | true | Ricarica automaticamente dopo create/update/delete |
Risultato CrudResourceResult
interface CrudResourceResult<T, CreateRequest, UpdateRequest> {
items: Ref<T[]>
loading: Ref<boolean>
error: Ref<string | null>
load: (filters?: Record<string, unknown>) => Promise<void>
create: (payload: CreateRequest) => Promise<T>
update?: (id: string, payload: UpdateRequest) => Promise<T>
delete?: (id: string) => Promise<void>
}
| Campo | Descrizione |
|---|---|
items | Ref<T[]> reattiva con la lista corrente |
loading | true durante load() |
error | Messaggio errore corrente o null. Settato solo da load() |
load(filters?) | Carica gli elementi. Aggiorna items, loading, error |
create(payload) | Crea elemento, ricarica se autoReload e ritorna l'elemento creato |
update(id, payload) | Presente solo se updateItem fornita. Throw se chiamata e non disponibile |
delete(id) | Presente solo se deleteItem fornita |
Errori CRUD diversi da
load: create, update, deletethrow in caso di errore (con messaggio estratto via extractErrorMessage). error.value viene aggiornato solo da load(). Catcha tu negli handler UI o usa useCrudView che lo fa per te.Esempio completo
import { useMfeContext } from '@pzeta/mfe-contracts/composables'
import { useCrudResource } from '@pzeta/mfe-contracts/composables'
interface Tag {
id: string
nome: string
colore: string
}
interface CreateTagRequest {
nome: string
colore: string
}
const ctx = useMfeContext()
const tags = useCrudResource<Tag, CreateTagRequest>({
resourceName: 'tag',
autoReload: true,
loadItems: async (filters) => {
const { data } = await ctx.http.get<Tag[]>('/api/tags', { params: filters })
return data
},
createItem: async (payload) => {
const { data } = await ctx.http.post<Tag>('/api/tags', payload)
return data
},
updateItem: async (id, payload) => {
const { data } = await ctx.http.put<Tag>(`/api/tags/${id}`, payload)
return data
},
deleteItem: async (id) => {
await ctx.http.delete(`/api/tags/${id}`)
},
})
// Uso
await tags.load({ active: true })
console.log(tags.items.value)
const nuovoTag = await tags.create({ nome: 'urgente', colore: '#dc2626' })
await tags.update!(nuovoTag.id, { colore: '#991b1b' })
await tags.delete!(nuovoTag.id)
Senza update/delete
Se la risorsa è read-create-only (audit log, eventi immutabili):
const events = useCrudResource<Event, CreateEventRequest>({
resourceName: 'eventi',
loadItems: async () => (await ctx.http.get<Event[]>('/api/events')).data,
createItem: async (p) => (await ctx.http.post<Event>('/api/events', p)).data,
// NO updateItem, NO deleteItem
})
events.update // undefined (non tipizzato sul risultato)
events.delete // undefined
Senza auto-reload
Per gestire manualmente quando ricaricare:
const resource = useCrudResource({
/* ... */
autoReload: false,
})
await resource.create(payload)
// resource.items non è ancora aggiornato
await resource.load() // ora sì
Utile quando vuoi ottimizzare ricaricando solo dopo bulk operations.
Bridge con useCrudView
Vedi useCrudViewFromResource per collegare automaticamente questo composable alla UI CRUD (dialog + handleEdit + handleDelete con conferma).
Tipi correlati
Identifiable—{ id: string }useCrudView— UI CRUD sopra questa risorsauseErrorToast— toast automatico suresource.errorextractErrorMessage— utility interna usata per i messaggi