/** * API module. * @module api */ import store from '@/store' import { handleResponse, handleError } from './handlers' import { objectToParams } from '@/helpers/commons' export default { options: { credentials: 'include', mode: 'cors', headers: { // FIXME is it important to keep this previous `Accept` header ? // 'Accept': 'application/json, text/javascript, */*; q=0.01', // Auto header is : // "Accept": "*/*", // Also is this still important ? (needed by back-end) 'X-Requested-With': 'XMLHttpRequest' } }, /** * Opens a WebSocket connection to the server in case it sends messages. * Currently, the connection is closed by the server right after an API call so * we have to open it for every calls. * Messages are dispatch to the store so it can handle them. * * @return {Promise} Promise that resolve on websocket 'open' or 'error' event. */ openWebSocket () { return new Promise(resolve => { const ws = new WebSocket(`wss://${store.getters.host}/yunohost/api/messages`) ws.onmessage = ({ data }) => store.dispatch('DISPATCH_MESSAGE', JSON.parse(data)) // ws.onclose = (e) => {} ws.onopen = resolve // Resolve also on error so the actual fetch may be called. ws.onerror = resolve }) }, /** * Generic method to fetch the api without automatic response handling. * * @param {string} method - a method between 'GET', 'POST', 'PUT' and 'DELETE'. * @param {string} uri * @param {string} [data={}] - data to send as body for 'POST', 'PUT' and 'DELETE' methods. * @return {Promise} Promise that resolve a fetch `Response`. */ async fetch (method, uri, data = {}) { // Open a websocket connection that will dispatch messages received. // FIXME add ability to do not open it await this.openWebSocket() if (method === 'GET') { const localeQs = `${uri.includes('?') ? '&' : '?'}locale=${store.getters.locale}` return fetch('/yunohost/api/' + uri + localeQs, this.options) } return fetch('/yunohost/api/' + uri, { ...this.options, method, body: objectToParams(data, { addLocale: true }) }) }, /** * Api get helper function. * * @param {string} uri - the uri to call. * @return {Promise} Promise that resolve the api response as an object, a string or as an error. */ get (uri) { return this.fetch('GET', uri).then(handleResponse) }, /** * Api get helper function for multiple queries. * * @param {string} uri - the uri to call. * @return {Promise} Promise that resolve the api responses as an array. */ getAll (uris) { return Promise.all(uris.map(uri => this.get(uri))) }, /** * Api post helper function. * * @param {string} uri - the uri to call. * @param {string} [data={}] - data to send as body. * @return {Promise} Promise that resolve the api responses as an array. */ post (uri, data = {}) { store.dispatch('WAITING_FOR_RESPONSE', [uri, 'POST']) return this.fetch('POST', uri, data).then(handleResponse) }, /** * Api put helper function. * * @param {string} uri - the uri to call. * @param {string} [data={}] - data to send as body. * @return {Promise} Promise that resolve the api responses as an array. */ put (uri, data = {}) { store.dispatch('WAITING_FOR_RESPONSE', [uri, 'PUT']) return this.fetch('PUT', uri, data).then(handleResponse) }, /** * Api delete helper function. * * @param {string} uri - the uri to call. * @param {string} [data={}] - data to send as body. * @return {Promise<('ok'|Error)>} Promise that resolve the api responses as an array. */ delete (uri, data = {}) { store.dispatch('WAITING_FOR_RESPONSE', [uri, 'DELETE']) return this.fetch('DELETE', uri, data).then(response => { store.dispatch('SERVER_RESPONDED') return response.ok ? 'ok' : handleError(response) }) } }