import { PrestashopRequestParameters } from './static/parameters'; // @ts-ignore import httpBuildQuery from 'http-build-query'; // @ts-ignore import base64 from 'base-64'; // @ts-ignore import objectToXml from 'object-to-xml'; import axios from 'axios'; const { httpBuildQuery: any } = httpBuildQuery; const { o2x } = objectToXml; interface PrestashopApiConfig { url: string; token: string; } export class PrestashopApi { private readonly config: PrestashopApiConfig; private readonly base64_token: string; constructor(config: PrestashopApiConfig) { this.config = config; this.base64_token = base64.encode(config.token); } private buildQuery(options: any) { let urlParams = {} as any; let query = ''; for (const keyOption of Object.keys(options)) { urlParams[keyOption] = options[keyOption]; } if (Object.entries(urlParams).length > 0) { query = `${httpBuildQuery(urlParams)}`; } return query; } private buildUrl(config: PrestashopApiConfig, params: PrestashopRequestParameters, deleteRequest = false) { if (deleteRequest && params.id) return `${config.url}api/${params.resource}/${params.id}?ws_key=${config.token}`; const query = this.buildQuery(params); let route = `${config.url}api/${params.resource}`; if (params.id) { route = `${route}/${params.id}`; } route = `${route}?ws_key=${config.token}&output_format=JSON&${query}${params._blank ? '&schema=blank' : ''}`; return route; } private adaptsBodyToLanguages(body: any): any { const formatBody = (resourceKey: string, bodyToFormat: any) => { for (const [key, value] of Object.entries(bodyToFormat[resourceKey])) { if (Array.isArray(value) && value.length > 0 && value[0].id && (value[0].value || value[0].value === null)) { bodyToFormat[resourceKey][key] = { language: bodyToFormat[resourceKey][key].map((val: { id: number, value: string }) => ({ '@': { id: val.id }, ...(val.value ? { '#': val.value } : {}) })) }; } } return bodyToFormat; }; if (Array.isArray(body) && body.length > 0) { const resourceKey = Object.keys(body[0])[0]; return { [resourceKey]: body.map((b) => formatBody(resourceKey, b)[resourceKey]) }; } else { const resourceKey = Object.keys(body)[0]; return formatBody(resourceKey, body); } } /** * Executes the query passed in parameter until it succeeds * @param query Query to execute * @param retry Current recurrence * @private */ private async executeQuery(query: () => Promise, retry = 0): Promise { if (retry >= 10) { return null; } try { const result = await query(); if (result.status !== 503) { return result.data; } } catch (error) { } const randomInt = Math.floor(Math.random() * (6000 - 3000 + 1)) + 3000; await new Promise((resolve) => setTimeout(resolve, randomInt)); return this.executeQuery(query, retry + 1); } /** * Retrieves data from the resource passed in parameter * @param params */ public async get(params: PrestashopRequestParameters) { const url = this.buildUrl(this.config, params); const query = async () => { try { const response = await axios.get(url, { headers: { 'Authorization': `Basic ${this.base64_token}`, 'Content-Type': 'application/json' } }); return response; } catch (error: any) { return error.response; } }; const response = await this.executeQuery(query); return response; } /** * Create data with a body * @param params * @param body */ public async post(params: PrestashopRequestParameters, body: any) { const url = this.buildUrl(this.config, params); const query = async () => { try { const response = await axios.post(url, o2x({ '?xml version=\"1.0\" encoding=\"UTF-8\"?': null, prestashop: this.adaptsBodyToLanguages(body) }), { headers: { 'Authorization': `Basic ${this.base64_token}`, 'Content-Type': 'application/xml' }, maxBodyLength: Infinity, maxContentLength: Infinity }); return response; } catch (error: any) { return error.response; } }; const response = await this.executeQuery(query); return response; } /** * Modify data by entering a body and filters * @param params * @param body */ public async put(params: PrestashopRequestParameters, body: any) { const url = this.buildUrl(this.config, params); const query = async () => { try { const response = await axios.put(url, o2x({ '?xml version=\"1.0\" encoding=\"UTF-8\"?': null, prestashop: this.adaptsBodyToLanguages(body) }), { headers: { 'Authorization': `Basic ${this.base64_token}`, 'Content-Type': 'text/xml' }, maxBodyLength: Infinity, maxContentLength: Infinity }); return response; } catch (error: any) { return error.response; } }; const response = await this.executeQuery(query); return response; } /** * Delete data by entering a body and filters * @param params */ public async delete(params: PrestashopRequestParameters) { const url = this.buildUrl(this.config, params, true); const query = async () => { try { const response = await axios.delete(url); return response; } catch (error: any) { return error.response; } }; const response = await this.executeQuery(query); return response; } }