UNPKG

@applica-software-guru/crud-client

Version:

Libreria per l'accesso ai servizi REST di Applica.

653 lines (509 loc) 17 kB
Libreria per l'accesso ai servizi REST di Applica. | Info | Dettagli | | --------------- | ------------------------------------------------------- | | Ultima versione | 1.0.\* | | Autore | Roberto Conte Rosito | | Repository | https://bitbucket.org/applicaguru/crud-client | | Pipeline | https://bitbucket.org/applicaguru/crud-client/pipelines | # Prefazione La libreria `@applica-software-guru/crud-client` è un client REST che consente l'accesso ai servizi REST di Applica. La sua implementazione si basa sui principi e le linee guida definite all'interno del progetto [React-Admin](https://marmelab.com/react-admin/Admin.html#dataprovider) # Installazione Per installare la libreria: ```bash npm install @applica-software-guru/crud-client ``` # Configurazione ## Configurazione Base ```javascript import { ApplicaDataProvider, createAttachmentsParser } from '@applica-software-guru/crud-client'; import { createAuthProvider, MemoryStorage } from '@applica-software-guru/iam-client'; import { HttpError } from 'ra-core'; const apiUrl = 'https://api.applica.guru/api'; const storage = new MemoryStorage(); const authProvider = createAuthProvider({ apiUrl, storage }); const dataProvider = new ApplicaDataProvider({ apiUrl, HttpErrorClass: HttpError, getHeaders: async () => await authProvider.getHeaders(), getToken: async () => await authProvider.getToken(), attachmentsParser: createAttachmentsParser() }); ``` ## Configurazione Avanzata ```javascript const dataProvider = new ApplicaDataProvider({ apiUrl: 'https://api.applica.guru/api', HttpErrorClass: HttpError, getHeaders: async () => await authProvider.getHeaders(), getToken: async () => await authProvider.getToken(), attachmentsParser: createAttachmentsParser(), // Opzionale: modalità mobile mobile: false, // default: false // Opzionale: timeout di default per tutte le richieste (in millisecondi) timeout: 30000, // default: 30000 (30 secondi) // Opzionale: funzione per preparare i dati prima dell'invio prepareData: (data, resource, params) => { // Personalizza i dati prima dell'invio return data; } }); ``` ### Configurazione per Applicazioni Mobile Se lavori su un'applicazione mobile devi necessariamente creare il data provider in questo modo: ```javascript const dataProvider = new ApplicaDataProvider({ apiUrl, // ... altre configurazioni mobile: true }); ``` In modalità mobile, il dataProvider adotta comportamenti diversi per le chiamate di creazione e modifica dei record: - Utilizza chiamate REST pure invece di FormData - La gestione degli upload dei file viene gestita separatamente # API Reference Il dataProvider implementa tutte le operazioni CRUD standard di React-Admin, estese con funzionalità specifiche di Applica. **🕒 Timeout Support:** Tutte le operazioni supportano un parametro `timeout` opzionale che sovrascrive il timeout globale configurato nel provider. Questo permette di personalizzare il timeout per ogni singola richiesta in base alle necessità specifiche dell'operazione. ## Operazioni CRUD Standard ### getList Recupera una lista paginata di record con supporto per filtri e ordinamento. ```javascript const result = await dataProvider.getList('entities/user', { pagination: { page: 1, perPage: 10 }, sort: { field: 'name', order: 'ASC' // o 'DESC' }, filter: { name__like: 'Giovanni', id__gt: 10, active__is: true, keyword: 'search term' // ricerca globale }, // Opzionale: timeout specifico per questa richiesta timeout: 5000 // 5 secondi }); // Risultato: // { // data: [...], // array di record // total: 150 // numero totale di record // } ``` **Operatori di filtro supportati:** - `__like`: ricerca LIKE - `__eq`: uguaglianza esatta - `__gt`: maggiore di - `__gte`: maggiore o uguale - `__lt`: minore di - `__lte`: minore o uguale - `__is`: valore booleano - `__in`: valore in array ### getOne Recupera un singolo record per ID. ```javascript const result = await dataProvider.getOne('entities/user', { id: 1, timeout: 3000 // timeout opzionale }); // Risultato: // { // data: { id: 1, name: 'Roberto', ... } // } ``` ### getMany Recupera più record specificando i loro ID. ```javascript const result = await dataProvider.getMany('entities/user', { ids: [1, 2, 3], timeout: 4000 }); // Risultato: // { // data: [ // { id: 1, name: 'Roberto' }, // { id: 2, name: 'Mario' }, // { id: 3, name: 'Luigi' } // ] // } ``` ### getManyReference Recupera record che referenziano un altro record. ```javascript const result = await dataProvider.getManyReference('entities/post', { target: 'author_id', id: 123, // ID dell'autore pagination: { page: 1, perPage: 10 }, sort: { field: 'title', order: 'ASC' }, filter: { published: true }, timeout: 6000 }); ``` ### create Crea un nuovo record. Supporta upload di file e allegati. ```javascript const result = await dataProvider.create('entities/user', { data: { name: 'Nuovo Utente', email: 'nuovo@example.com', avatar: fileObject, // File object per upload documents: [file1, file2] // Array di file }, timeout: 10000 // timeout più lungo per upload }); // Risultato: // { // data: { id: 456, name: 'Nuovo Utente', ... } // } ``` ### update Aggiorna un record esistente. ```javascript const result = await dataProvider.update('entities/user', { id: 1, data: { name: 'Nome Aggiornato', email: 'aggiornato@example.com' }, previousData: { id: 1, name: 'Vecchio Nome', ... }, // richiesto da React-Admin timeout: 8000 }); ``` ### updateMany Aggiorna più record contemporaneamente. ```javascript const result = await dataProvider.updateMany('entities/user', { ids: [1, 2, 3], data: { status: 'active' }, rows: [ // dati specifici per ogni record (opzionale) { id: 1, name: 'Roberto' }, { id: 2, name: 'Mario' }, { id: 3, name: 'Luigi' } ], timeout: 15000 }); ``` ### delete Elimina un record. ```javascript const result = await dataProvider.delete('entities/user', { id: 1, timeout: 5000 }); ``` ### deleteMany Elimina più record contemporaneamente. ```javascript const result = await dataProvider.deleteMany('entities/user', { ids: [1, 2, 3], timeout: 10000 }); ``` ## Operazioni Estese ### get Esegue una chiamata GET generica. Supporta timeout configurabile per richiesta. ```javascript // Chiamata GET di base const result = await dataProvider.get('users', { name: 'Roberto', active: true }); // Con timeout personalizzato const result = await dataProvider.get('users', { name: 'Roberto', active: true, timeout: 5000 // 5 secondi per questa richiesta }); ``` ### post Esegue una chiamata POST generica. Supporta timeout configurabile per richiesta. ```javascript import { stringify } from 'query-string'; // Chiamata POST di base const result = await dataProvider.post(`users?${stringify({ k: 'f' })}`, { id: 1, name: 'Roberto' }); // Con timeout personalizzato const result = await dataProvider.post('users', { id: 1, name: 'Roberto', timeout: 10000 // 10 secondi per questa richiesta }); ``` ### getFile Scarica un file dal server mantenendo l'autenticazione. ```javascript const fileUrl = await dataProvider.getFile('/attachments/post/1/picture/1'); // Utilizzo per download const link = document.createElement('a'); link.href = fileUrl; link.download = 'filename.jpg'; link.click(); ``` ### getApiUrl Ottiene l'URL base dell'API configurato. ```javascript const apiUrl = dataProvider.getApiUrl(); console.log(apiUrl); // 'https://api.applica.guru/api' ``` # Gestione Timeout Ogni operazione supporta un timeout configurabile a livello di singola richiesta, che sovrascrive il timeout di default del provider. ## Timeout di Default ```javascript const dataProvider = new ApplicaDataProvider({ // ... altre configurazioni timeout: 30000 // 30 secondi per tutte le richieste }); ``` ## Timeout per Richiesta Specifica ```javascript // Timeout specifico sovrascrive quello di default await dataProvider.getList('users', { pagination: { page: 1, perPage: 10 }, timeout: 5000 // Solo questa richiesta avrà timeout di 5 secondi }); // Timeout per operazioni di upload (solitamente più lunghi) await dataProvider.create('documents', { data: { file: largeFileObject }, timeout: 60000 // 1 minuto per upload di file grandi }); ``` ## Gestione Errori di Timeout ```javascript try { const result = await dataProvider.getList('users', { pagination: { page: 1, perPage: 10 }, timeout: 1000 // timeout molto breve }); } catch (error) { if (error.message === 'error.request_timeout') { console.log('La richiesta è andata in timeout'); // Gestisci l'errore di timeout } } ``` ## Gestione Timeout Globale vs Locale Il sistema di timeout del dataProvider funziona su due livelli: **globale** e **locale**. ### Timeout Globale Il timeout globale è configurato una sola volta durante l'istanziazione del dataProvider e si applica a tutte le richieste come valore di default. È particolarmente utile per: - Definire un timeout standard per tutta l'applicazione - Evitare di specificare il timeout per ogni singola chiamata - Gestire connessioni lente o instabili con un valore appropriato ```javascript // Configurazione globale - si applica a tutte le operazioni const dataProvider = new ApplicaDataProvider({ apiUrl: 'https://api.applica.guru/api', timeout: 15000 // 15 secondi per TUTTE le richieste // ... altre configurazioni }); // Tutte queste chiamate useranno il timeout di 15 secondi await dataProvider.getList('users', { pagination: { page: 1, perPage: 10 } }); await dataProvider.getOne('users', { id: 1 }); await dataProvider.create('users', { data: { name: 'Roberto' } }); ``` ### Timeout Locale Il timeout locale è specificato per ogni singola operazione e **sovrascrive** il timeout globale solo per quella chiamata specifica. È ideale per: - Operazioni che richiedono più tempo (upload di file, export di dati) - Operazioni critiche che necessitano di risposta rapida - Adattare il timeout in base al tipo di operazione ```javascript // Il dataProvider ha un timeout globale di 15 secondi const dataProvider = new ApplicaDataProvider({ timeout: 15000 // timeout globale // ... }); // Timeout locale: questa chiamata aspetterà solo 3 secondi await dataProvider.getList('users', { pagination: { page: 1, perPage: 10 }, timeout: 3000 // SOVRASCRIVE il timeout globale per questa chiamata }); // Upload con timeout esteso: questa chiamata aspetterà 2 minuti await dataProvider.create('documents', { data: { file: largeFile }, timeout: 120000 // SOVRASCRIVE il timeout globale per questa chiamata }); // Questa chiamata userà il timeout globale di 15 secondi (nessun timeout locale specificato) await dataProvider.getOne('users', { id: 1 }); ``` ### Strategia di Timeout Consigliata ```javascript // Configurazione ottimale per la maggior parte delle applicazioni const dataProvider = new ApplicaDataProvider({ timeout: 30000 // 30 secondi come default sicuro // ... }); // Operazioni veloci - timeout ridotto await dataProvider.getOne('config', { id: 1, timeout: 5000 }); // Operazioni normali - usa il timeout globale await dataProvider.getList('users', { pagination: { page: 1, perPage: 10 } }); // Upload/download - timeout esteso await dataProvider.create('files', { data: { file: bigFile }, timeout: 300000 // 5 minuti per file molto grandi }); // Operazioni critiche real-time - timeout molto breve await dataProvider.get('system/status', { timeout: 2000 }); // Chiamate POST personalizzate con timeout await dataProvider.post('analytics/report', { startDate: '2024-01-01', endDate: '2024-12-31', timeout: 45000 // 45 secondi per report complessi }); ``` La **precedenza** è sempre: **Timeout Locale > Timeout Globale > Default di Sistema (30 secondi)** **Operazioni che supportano timeout personalizzato:** - `getList`, `getOne`, `getMany`, `getManyReference` - Tutte le operazioni di lettura - `create`, `update`, `updateMany` - Tutte le operazioni di scrittura - `delete`, `deleteMany` - Tutte le operazioni di eliminazione - `get`, `post` - Chiamate generiche GET e POST # Gestione File e Allegati Il dataProvider include supporto integrato per il caricamento di file e allegati. ## Parser per Allegati ```javascript import { createAttachmentsParser } from '@applica-software-guru/crud-client'; // Configurazione di base const attachmentsParser = createAttachmentsParser(); // Configurazione personalizzata const customAttachmentsParser = createAttachmentsParser({ images: ['avatar', 'thumbnail', 'banner'], files: ['document', 'pdf', 'contract'], attachments: ['gallery'] // array di file }); ``` ## Upload di File ```javascript const fileInput = document.querySelector('input[type="file"]'); const file = fileInput.files[0]; const result = await dataProvider.create('entities/document', { data: { title: 'Documento Importante', file: file, // File object images: [image1, image2], // Array di immagini metadata: { category: 'important' } } }); ``` # Gestione Errori Il dataProvider utilizza una classe di errore configurabile per gestire gli errori HTTP. ```javascript import { HttpError } from 'ra-core'; const dataProvider = new ApplicaDataProvider({ // ... altre configurazioni HttpErrorClass: HttpError }); ``` ## Codici di Errore Standard - `401`: `iam.error.unauthorized` - Non autorizzato - `403`: `iam.error.forbidden` - Accesso negato - `404`: `error.not_found` - Risorsa non trovata - `408`: `error.request_timeout` - Timeout richiesta - Errori di validazione: `error.validation` - Errori generici: `error.generic` ## Gestione degli Errori ```javascript try { const result = await dataProvider.getOne('users', { id: 999 }); } catch (error) { switch (error.message) { case 'iam.error.unauthorized': // Reindirizza al login break; case 'error.not_found': // Mostra messaggio "utente non trovato" break; case 'error.request_timeout': // Mostra opzione per ritentare break; default: // Errore generico console.error('Errore:', error); } } ``` # Utilizzo con React-Admin Il dataProvider è completamente compatibile con React-Admin: ```javascript import { Admin, Resource } from 'react-admin'; import { ApplicaDataProvider } from '@applica-software-guru/crud-client'; const dataProvider = new ApplicaDataProvider({ // configurazione... }); function App() { return ( <Admin dataProvider={dataProvider}> <Resource name="users" list={UserList} edit={UserEdit} create={UserCreate} /> </Admin> ); } ``` # Migrazione dalla Versione Precedente Se stai utilizzando la funzione deprecata `createDataProvider`, migra alla nuova sintassi: ```javascript // DEPRECATO ❌ import { createDataProvider } from '@applica-software-guru/crud-client'; const dataProvider = createDataProvider(config); // NUOVO ✅ import { ApplicaDataProvider } from '@applica-software-guru/crud-client'; const dataProvider = new ApplicaDataProvider(config); ``` # Esempi Avanzati ## Configurazione Completa per Produzione ```javascript import { ApplicaDataProvider, createAttachmentsParser } from '@applica-software-guru/crud-client'; import { createAuthProvider, MemoryStorage } from '@applica-software-guru/iam-client'; import { HttpError } from 'ra-core'; const apiUrl = process.env.REACT_APP_API_URL; const storage = new MemoryStorage(); const authProvider = createAuthProvider({ apiUrl, storage }); const dataProvider = new ApplicaDataProvider({ apiUrl, HttpErrorClass: HttpError, getHeaders: async () => await authProvider.getHeaders(), getToken: async () => await authProvider.getToken(), attachmentsParser: createAttachmentsParser({ images: ['avatar', 'banner', 'thumbnail'], files: ['cv', 'document', 'contract'], attachments: ['gallery', 'portfolio'] }), timeout: 15000, // 15 secondi timeout di default prepareData: (data, resource, params) => { // Aggiungi timestamp a tutti i record return { ...data, updatedAt: new Date().toISOString() }; } }); export { dataProvider, authProvider }; ``` ## Gestione Avanzata degli Upload ```javascript // Upload con progress tracking const uploadDocument = async (file, onProgress) => { try { const result = await dataProvider.create('documents', { data: { title: file.name, file: file, category: 'user-upload' }, timeout: 120000 // 2 minuti per file grandi }); onProgress(100); return result; } catch (error) { if (error.message === 'error.request_timeout') { throw new Error('Upload timeout - il file potrebbe essere troppo grande'); } throw error; } }; ```