UNPKG

@applica-software-guru/crud-client

Version:

Libreria per l'accesso ai servizi REST di Applica.

378 lines (354 loc) 11.8 kB
import { ApplicaDataProviderConfig, AttachmentParserResult, CreateParamsExtended, DeleteManyParamsExtended, DeleteParamsExtended, GetListParamsExtended, GetManyParamsExtended, GetManyReferenceParamsExtended, GetOneParamsExtended, IApplicaDataProvider, UpdateManyParamsExtended, UpdateParamsExtended } from './types'; import { createFormData, createGetQuery, fetchJson } from './utils'; import { stringify } from 'query-string'; import { CreateParams, CreateResult, DeleteManyResult, DeleteResult, GetListResult, GetManyReferenceResult, GetManyResult, GetOneResult, Identifier, UpdateManyResult, UpdateParams, UpdateResult } from 'ra-core'; class ApplicaDataProvider implements IApplicaDataProvider { config: ApplicaDataProviderConfig; prepareData: (data: any, resource?: string, params?: CreateParams | UpdateParams | any) => any; prepareAttachments: (data: any) => Promise<AttachmentParserResult>; private timeout: number; constructor(config: ApplicaDataProviderConfig) { this.config = config; this.prepareData = config.prepareData || ((data: any) => data); this.prepareAttachments = config.attachmentsParser; this.timeout = config.timeout || 30000; // Default 30 seconds } /** * @inheritdoc */ getApiUrl(): string { return this.config.apiUrl; } /** * @inheritdoc */ async getFile(resource: string): Promise<string> { const headers = await this.config.getHeaders(); return fetch(`${this.config.apiUrl}${resource}`, { headers }) .then((response) => response.blob()) .then((blob) => URL.createObjectURL(blob)); } /** * @inheritdoc */ async getList(resource: string, params: GetListParamsExtended | any): Promise<GetListResult | any> { const query = createGetQuery(params); const url = `${this.config.apiUrl}/${resource}/find`; const headers = await this.config.getHeaders(); const options = { headers, body: JSON.stringify(query), method: 'POST' }; const timeout = params?.timeout || this.timeout; return fetchJson(url, options, this.config.HttpErrorClass, timeout).then(({ json }) => ({ data: json?.value?.rows, total: parseInt(json?.value?.totalRows) })); } /** * @inheritdoc */ async getOne(resource: string, params: GetOneParamsExtended | any): Promise<GetOneResult | any> { const url = `${this.config.apiUrl}/${resource}` + (params.id ? `/${params.id}` : ''); const headers = await this.config.getHeaders(); const options = { headers }; const timeout = params?.timeout || this.timeout; return fetchJson(url, options, this.config.HttpErrorClass, timeout).then(({ json }) => ({ data: json.value })); } /** * @inheritdoc */ async getMany(resource: string, params: GetManyParamsExtended | any): Promise<GetManyResult | any> { const url = `${this.config.apiUrl}/${resource}/find`; const headers = await this.config.getHeaders(); const options = { headers, body: JSON.stringify({ filters: [ { property: 'id', value: params.ids, type: 'in' } ] }), method: 'POST' }; const timeout = params?.timeout || this.timeout; return fetchJson(url, options, this.config.HttpErrorClass, timeout).then(({ json }) => ({ data: json?.value?.rows, total: parseInt(json?.value?.totalRows) })); } /** * @inheritdoc */ async getManyReference(resource: string, params: GetManyReferenceParamsExtended): Promise<GetManyReferenceResult> { const query = createGetQuery(params); const url = `${this.config.apiUrl}/${resource}/find`; const headers = await this.config.getHeaders(); query.filters.push({ property: params.target, value: params.id, type: 'eq' }); const options = { headers, body: JSON.stringify(query), method: 'POST' }; const timeout = params?.timeout || this.timeout; return fetchJson(url, options, this.config.HttpErrorClass, timeout).then(({ json }) => ({ data: json?.value?.rows, total: parseInt(json?.value?.totalRows) })); } /** * @inheritdoc */ async create(resource: string, params: CreateParamsExtended): Promise<CreateResult> { return this.prepareAttachments(params.data).then(async ({ data, parts }) => { const url = `${this.config.apiUrl}/${resource}`; const token = await this.config.getToken(); let body: any = null; let headers: any = {}; if (this.config.mobile === true) { body = this.prepareData(data, resource, params); body = JSON.stringify(body); headers = { 'Content-Type': 'application/json' }; } else { body = new FormData(); const jsonData = JSON.stringify(this.prepareData(data, resource, params)); const entity = new Blob([jsonData], { type: 'application/json' }); body.append('entity', entity); parts.forEach((p) => body.append(p.id, p.file)); } const options = this.createOptions( { method: 'POST', body, headers }, token ); const timeout = params?.timeout || this.timeout; return fetchJson(url, options, this.config.HttpErrorClass, timeout).then(({ json }) => ({ data: { ...(json?.value || params.data), id: json?.value.id } })); }); } /** * @inheritdoc */ async update(resource: string, params: UpdateParamsExtended): Promise<UpdateResult> { return this.prepareAttachments(params.data).then(async ({ data, parts }) => { const url = `${this.config.apiUrl}/${resource}`; const token = await this.config.getToken(); let body: any = null; let headers: any = {}; if (this.config.mobile === true) { body = this.prepareData(data, resource, params); body = JSON.stringify(body); headers = { 'Content-Type': 'application/json' }; } else { body = new FormData(); const jsonData = JSON.stringify(this.prepareData(data, resource, params)); const entity = new Blob([jsonData], { type: 'application/json' }); body.append('entity', entity); parts.forEach((p) => body.append(p.id, p.file)); } const options = this.createOptions( { method: 'POST', body, headers }, token ); const timeout = params?.timeout || this.timeout; return fetchJson(url, options, this.config.HttpErrorClass, timeout).then(({ json }) => ({ data: { ...(json?.value || params.data), id: json?.value.id } })); }); } /** * @inheritdoc */ async updateMany( resource: string, params: UpdateManyParamsExtended & { rows?: any[]; } ): Promise<UpdateManyResult> { const token = await this.config.getToken(); const timeout = params?.timeout || this.timeout; return Promise.all( params.ids.map((id: Identifier) => fetchJson( `${this.config.apiUrl}/${resource}`, { method: 'POST', body: (() => { if (this.config.mobile === true) { const row = params?.rows?.[id as number] || params?.rows?.find((r: any) => r.id === id); const entity = JSON.stringify(this.prepareData({ ...row, ...params.data, id })); return entity; } else { const row = params?.rows?.[id as number] || params?.rows?.find((r: any) => r.id === id); const jsonData = JSON.stringify(this.prepareData({ ...row, ...params.data, id })); const entity = new Blob([jsonData], { type: 'application/json' }); const formData = new FormData(); formData.append('entity', entity); return formData; } })(), headers: (() => this.config.mobile === true ? this.createHeaders( { 'Content-Type': 'application/json' }, token ) : this.createHeaders({}, token))() }, this.config.HttpErrorClass, timeout ).then(({ json }) => ({ data: { ...(json?.value || params.data), id: json?.value.id } })) ) ).then((responses) => ({ data: responses.map((response) => response.data) })); } /** * @inheritdoc */ async delete(resource: string, params: DeleteParamsExtended | any): Promise<DeleteResult | any> { const url = `${this.config.apiUrl}/${resource}/delete`; const token = await this.config.getToken(); const body = createFormData({ ids: params.id }); const options = this.createOptions( { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', Accept: 'application/json' }, body }, token ); const timeout = params?.timeout || this.timeout; return fetchJson(url, options, this.config.HttpErrorClass, timeout).then(({ json }) => ({ data: json })); } /** * @inheritdoc */ async deleteMany(resource: string, params: DeleteManyParamsExtended | any): Promise<DeleteManyResult | any> { const token = await this.config.getToken(); const url = `${this.config.apiUrl}/${resource}/delete`; const options = this.createOptions( { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', Accept: 'application/json' }, body: createFormData({ ids: params.ids }) }, token ); const timeout = params?.timeout || this.timeout; return fetchJson(url, options, this.config.HttpErrorClass, timeout).then(() => ({ data: params.ids })); } private async _call(method: string, resource: string, params: any, timeout?: number): Promise<any> { let url = `${this.config.apiUrl}/${resource}`; // Extract timeout from params if not explicitly provided const requestTimeout = timeout || params?.timeout || this.timeout; // Create a copy of params without timeout for the actual request const requestParams = params ? { ...params } : {}; if (requestParams.timeout) { delete requestParams.timeout; } if (method === 'GET' && requestParams && Object.keys(requestParams).length > 0) { const queryString = stringify(requestParams); url = `${this.config.apiUrl}/${resource}?${queryString}`; } const headers = await this.config.getHeaders(); const options = { method, headers, body: method !== 'GET' ? JSON.stringify(requestParams) : undefined }; return fetchJson(url, options, this.config.HttpErrorClass, requestTimeout).then(({ json }) => ({ data: json })); } /** * @inheritdoc */ async post(resource: string, params: any & { timeout?: number }): Promise<any> { return this._call('POST', resource, params); } /** * @inheritdoc */ async get(resource: string, params: any & { timeout?: number }): Promise<any> { return this._call('GET', resource, params); } private createHeaders(headers: any, token?: string) { const authHeaders = typeof token === 'string' && token !== undefined && token !== null ? { Authorization: `Bearer ${token}` } : {}; return { ...headers, ...authHeaders }; } private createOptions(options: any, token?: string): any { const headers = this.createHeaders(options?.headers, token); return { ...options, headers }; } } export { ApplicaDataProvider };