function onError(res, apiMethod, params) {
res.data = res.data || {};
normalizeResponse(res);
switch (res.status) {
// Wrong headers
case 0:
res.data.errorMessage = ErrorReasons.WrongHeader.description;
Toast.notify(res.data.errorMessage, res.data.errors).show();
return Promise.reject(ErrorReasons.WrongHeader);
// Bad Request
case 400:
// Error handling should be processed by request caller.
// Common error message for this case
res.data.errorMessage = ErrorReasons.BadRequest.description;
return Promise.reject(res);
// Unauthorized
case 401:
res.data.errorMessage = ErrorReasons.Unauthorized.description;
Toast.notify(res.data.errorMessage, res.data.errors).show();
return Promise.reject(ErrorReasons.Unauthorized);
// Forbidden
case 403:
return Toast.prompt().show();
// Internal Server Error
case 500:
return new Promise((resolve, reject) => {
Toast.prompt(res.data.errors)
.show()
.then(() => {
return apiMethod(params)
.then((val) => {
resolve(val);
})
.catch((res) => {
return onError(res, apiMethod, params)
.then(resolve)
.catch(reject);
});
})
.catch(() => reject(res));
});
// Not Found
case 404:
return new Promise(function(resolve, reject) {
res.data.errorMessage = ErrorReasons.NotFound.description;
Toast.notify(res.data.errorMessage, res.data.errors).show();
reject(res);
});
}
}
Example 1
function onError(res, apiMethod, params) {
res.data = res.data || {};
normalizeResponse(res);
switch (res.status) {
// Wrong headers
case 0:
return handleWrongHeaders({res});
// Bad Request
case 400:
return handleBadRequest({res});
// Unauthorized
case 401:
return handleUnauthorized({res});
// Forbidden
case 403:
return handleForbidden();
// Internal Server Error
case 500:
return handleInternalServerError({res, apiMethod, params});
// Not Found
case 404:
return handleNotFound({res});
}
}
function handleWrongHeaders({res}) {
res.data.errorMessage = ErrorReasons.WrongHeader.description;
Toast.notify(res.data.errorMessage, res.data.errors).show();
return Promise.reject(ErrorReasons.WrongHeader);
}
function handleBadRequest({res}) {
// Error handling should be processed by request caller.
// Common error message for this case
res.data.errorMessage = ErrorReasons.BadRequest.description;
return Promise.reject(res);
}
function handleUnauthorized({res}) {
res.data.errorMessage = ErrorReasons.Unauthorized.description;
Toast.notify(res.data.errorMessage, res.data.errors).show();
return Promise.reject(ErrorReasons.Unauthorized);
}
function handleForbidden() {
return Toast.prompt().show();
}
function handleInternalServerError({res, params, apiMethod}) {
return new Promise((resolve, reject) => {
Toast.prompt(res.data.errors)
.show()
.then(() => {
return apiMethod(params)
.then((val) => {
resolve(val);
})
.catch((res) => {
return onError(res, apiMethod, params)
.then(resolve)
.catch(reject);
});
})
.catch(() => reject(res));
});
}
function handleNotFound({res}) {
return new Promise(function(resolve, reject) {
res.data.errorMessage = ErrorReasons.NotFound.description;
Toast.notify(res.data.errorMessage, res.data.errors).show();
reject(res);
});
}
Blocks Are Extracted
const STATUS = {
WRONG_HEADERS: 0,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
INTERNAL_SERVER_ERROR: 500,
NOT_FOUND: 404
};
function onError(res, apiMethod, params) {
// res.data = res.data || {};
// has gone into normalizeResponse, seems reasonable place for normalization
normalizeResponse(res);
switch (res.status) {
case STATUS.WRONG_HEADERS:
return handleWrongHeaders({res});
case STATUS.BAD_REQUEST:
return handleBadRequest({res});
case STATUS.UNAUTHORIZED:
return handleUnauthorized({res});
case STATUS.FORBIDDEN:
return handleForbidden();
case STATUS.INTERNAL_SERVER_ERROR:
return handleInternalServerError({res, apiMethod, params});
case STATUS.NOT_FOUND:
return handleNotFound({res});
}
}
function handleWrongHeaders({res}) {
res.data.errorMessage = ErrorReasons.WrongHeader.description;
Toast.notify(res.data.errorMessage, res.data.errors).show();
return Promise.reject(ErrorReasons.WrongHeader);
}
function handleBadRequest({res}) {
// Error handling should be processed by request caller.
// Common error message for this case
res.data.errorMessage = ErrorReasons.BadRequest.description;
return Promise.reject(res);
}
function handleUnauthorized({res}) {
res.data.errorMessage = ErrorReasons.Unauthorized.description;
Toast.notify(res.data.errorMessage, res.data.errors).show();
return Promise.reject(ErrorReasons.Unauthorized);
}
function handleForbidden() {
return Toast.prompt().show();
}
function handleInternalServerError({res, params, apiMethod}) {
return new Promise((resolve, reject) => {
Toast.prompt(res.data.errors)
.show()
.then(() => {
return apiMethod(params)
.then((val) => {
resolve(val);
})
.catch((res) => {
return onError(res, apiMethod, params)
.then(resolve)
.catch(reject);
});
})
.catch(() => reject(res));
});
}
function handleNotFound({res}) {
return new Promise(function(resolve, reject) {
res.data.errorMessage = ErrorReasons.NotFound.description;
Toast.notify(res.data.errorMessage, res.data.errors).show();
reject(res);
});
}
Removed magic numbers
Removed redundant comments
const STATUS = {
WRONG_HEADERS: 0,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
INTERNAL_SERVER_ERROR: 500,
NOT_FOUND: 404
};
function onError(res, apiMethod, params) {
normalizeResponse(res);
const status = res.status;
const handlersMap = getDefaultHandlers();
if (handlersMap.hasOwnProperty(status)) {
return handlersMap[status]({res, apiMethod, params})
}
}
function getDefaultHandlers() {
return {
[STATUS.WRONG_HEADERS]: handleWrongHeaders,
[STATUS.BAD_REQUEST]: handleBadRequest,
[STATUS.UNAUTHORIZED]: handleUnauthorized,
[STATUS.FORBIDDEN]: handleForbidden,
[STATUS.INTERNAL_SERVER_ERROR]: handleInternalServerError,
[STATUS.NOT_FOUND]: handleNotFound
};
}
function handleWrongHeaders({res}) {
res.data.errorMessage = ErrorReasons.WrongHeader.description;
Toast.notify(res.data.errorMessage, res.data.errors).show();
return Promise.reject(ErrorReasons.WrongHeader);
}
function handleBadRequest({res}) {
// Error handling should be processed by request caller.
// Common error message for this case
res.data.errorMessage = ErrorReasons.BadRequest.description;
return Promise.reject(res);
}
function handleUnauthorized({res}) {
res.data.errorMessage = ErrorReasons.Unauthorized.description;
Toast.notify(res.data.errorMessage, res.data.errors).show();
return Promise.reject(ErrorReasons.Unauthorized);
}
function handleForbidden() {
return Toast.prompt().show();
}
function handleInternalServerError({res, params, apiMethod}) {
return new Promise((resolve, reject) => {
Toast.prompt(res.data.errors)
.show()
.then(() => {
return apiMethod(params)
.then((val) => {
resolve(val);
})
.catch((res) => {
return onError(res, apiMethod, params)
.then(resolve)
.catch(reject);
});
})
.catch(() => reject(res));
});
}
function handleNotFound({res}) {
return new Promise(function(resolve, reject) {
res.data.errorMessage = ErrorReasons.NotFound.description;
Toast.notify(res.data.errorMessage, res.data.errors).show();
reject(res);
});
}
Extract handlers
function onError(res, apiMethod, params, handlers = {}) {
const handlersMap = {
...getDefaultHandlers(),
...handlers
};
const {status} = res;
if (handlersMap.hasOwnProperty(status)) {
return handlersMap[status]({res, apiMethod, params})
}
}
Is it one responsibility?
function onError(res, apiMethod, params) {
const handlersMap = getDefaultHandlers();
const {status} = res;
const handle = getHandlerByStatus(handlersMap, status);
return handle({res, apiMethod, params});
}
function getHandlerByStatus(handlersMap, status) {
if (handlersMap.hasOwnProperty(status)) {
return handlersMap[status];
}
if (handlersMap.hasOwnProperty(STATUS.DEFAULT)) {
return handlersMap[STATUS.DEFAULT];
}
return noop;
}
function onError(res, apiMethod, params, handlers) {
const {status} = res;
const handle = getHandlerByStatus(handlers, status);
return handle({res, apiMethod, params});
}
Table Method example
By Semyon Radionov
Table Method example
- 745