separate handlers and helpers from api module

This commit is contained in:
Axolotle 2020-10-12 17:27:40 +02:00
parent 336165d7ea
commit 32ca7e11ec
4 changed files with 87 additions and 85 deletions

View file

@ -1,93 +1,12 @@
/** /**
* api module. * API module.
* @module api * @module api
*/ */
import store from '@/store' import store from '@/store'
import { handleResponse, handleError } from './handlers'
import { objectToParams } from '@/helpers/commons'
/**
* Allow to set a timeout on a `Promise` expected response.
* The returned Promise will be rejected if the original Promise is not resolved or
* rejected before the delay.
*
* @param {Promise} promise - A promise (like a fetch call).
* @param {number} delay - delay after which the promise is rejected
* @return {Promise}
*/
export function timeout (promise, delay) {
return new Promise((resolve, reject) => {
setTimeout(() => (reject(new Error('api_not_responding'))), delay)
promise.then(resolve, reject)
})
}
/**
* Converts an object literal into an `URLSearchParams` that can be turned into a
* query string or used as a body in a `fetch` call.
*
* @param {Object} object - An object literal to convert.
* @param {Object} options
* @param {boolean} [options.addLocale=false] - Option to append the locale to the query string.
* @return {URLSearchParams}
*/
export function objectToParams (object, { addLocale = false } = {}) {
const urlParams = new URLSearchParams()
for (const [key, value] of Object.entries(object)) {
if (Array.isArray(value)) {
value.forEach(v => urlParams.append(key, v))
} else {
urlParams.append(key, value)
}
}
if (addLocale) {
urlParams.append('locale', store.getters.locale)
}
return urlParams
}
/**
* Handler for api responses.
*
* @param {Response} response - A fetch `Response` object.
* @return {DigestedResponse} Parsed response's json, response's text or an error.
*/
export async function handleResponse (response) {
store.dispatch('SERVER_RESPONDED')
if (!response.ok) return handleErrors(response)
// FIXME the api should always return json objects
const responseText = await response.text()
try {
return JSON.parse(responseText)
} catch {
return responseText
}
}
/**
* Handler for API errors.
*
* @param {Response} response - A fetch `Response` object.
* @throws Will throw an error with the API response text or custom message.
*/
export async function handleErrors (response) {
if (response.status === 401) {
store.dispatch('DISCONNECT')
throw new Error('Unauthorized')
} else if (response.status === 400) {
const message = await response.text()
throw new Error(message)
}
}
/**
* A digested fetch response as an object, a string or an error.
* @typedef {(Object|string|Error)} DigestedResponse
*/
/**
* Actual api module.
* @module api/default
*/
export default { export default {
options: { options: {
credentials: 'include', credentials: 'include',
@ -201,7 +120,7 @@ export default {
store.dispatch('WAITING_FOR_RESPONSE', [uri, 'DELETE']) store.dispatch('WAITING_FOR_RESPONSE', [uri, 'DELETE'])
return this.fetch('DELETE', uri, data).then(response => { return this.fetch('DELETE', uri, data).then(response => {
store.dispatch('SERVER_RESPONDED') store.dispatch('SERVER_RESPONDED')
return response.ok ? 'ok' : handleErrors(response) return response.ok ? 'ok' : handleError(response)
}) })
} }
} }

39
app/src/api/handlers.js Normal file
View file

@ -0,0 +1,39 @@
import store from '@/store'
/**
* Handler for API responses.
*
* @param {Response} response - A fetch `Response` object.
* @return {DigestedResponse} Parsed response's json, response's text or an error.
*/
async function handleResponse (response) {
if (!response.ok) return handleError(response)
// FIXME the api should always return json objects
const responseText = await response.text()
try {
return JSON.parse(responseText)
} catch {
return responseText
}
}
/**
* Handler for API errors.
*
* @param {Response} response - A fetch `Response` object.
* @throws Will throw an error with the API response text or custom message.
*/
async function handleError (response) {
if (response.status === 401) {
store.dispatch('DISCONNECT')
throw new Error('Unauthorized')
} else if (response.status === 400) {
const message = await response.text()
throw new Error(message)
}
}
export {
handleResponse,
handleError
}

2
app/src/api/index.js Normal file
View file

@ -0,0 +1,2 @@
export { default } from './api'
export { handleResponse, handleError } from './handlers'

View file

@ -0,0 +1,42 @@
import store from '@/store'
/**
* Allow to set a timeout on a `Promise` expected response.
* The returned Promise will be rejected if the original Promise is not resolved or
* rejected before the delay.
*
* @param {Promise} promise - A promise (like a fetch call).
* @param {number} delay - delay after which the promise is rejected
* @return {Promise}
*/
export function timeout (promise, delay) {
return new Promise((resolve, reject) => {
// FIXME reject(new Error('api_not_responding')) for post-install
setTimeout(() => reject, delay)
promise.then(resolve, reject)
})
}
/**
* Converts an object literal into an `URLSearchParams` that can be turned into a
* query string or used as a body in a `fetch` call.
*
* @param {Object} object - An object literal to convert.
* @param {Object} options
* @param {boolean} [options.addLocale=false] - Option to append the locale to the query string.
* @return {URLSearchParams}
*/
export function objectToParams (object, { addLocale = false } = {}) {
const urlParams = new URLSearchParams()
for (const [key, value] of Object.entries(object)) {
if (Array.isArray(value)) {
value.forEach(v => urlParams.append(key, v))
} else {
urlParams.append(key, value)
}
}
if (addLocale) {
urlParams.append('locale', store.getters.locale)
}
return urlParams
}