Skip to content

Instantly share code, notes, and snippets.

@kottenator
Last active April 15, 2022 13:49
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kottenator/433f677e5fdddf78d195 to your computer and use it in GitHub Desktop.
Save kottenator/433f677e5fdddf78d195 to your computer and use it in GitHub Desktop.
JS error parser for django-rest-framework
/**
* Specific error parser for django-rest-framework errors structure
* Tested on django-rest-framework v2.3.13
* Live example at http://jsbin.com/wiqumo
*
* Error structure examples:
*
* // The most simple case
* { detail: "Authentication is required" }
*
* // Simple form validation error
* { title: ["This field is required."], "description": ["This field is required."]}
*
* // Simple list validation error
* [{}, {"title": ["This field is required."]}]
*
* // Complex nested object validation error
* {"experience": [
* {}, {}, {"position": ["This field is required."], "employer": ["This field is required."]}
* ]}
*/
_.parseErrors = function(data) {
function _camelCaseToVerbose(text) {
return text.replace(/(?=[A-Z])/g, ' ');
}
function _underscoredToVerbose(text) {
return text.replace(/[\d_]/g, ' ');
}
function _capitalize(text) {
text = text.toLowerCase();
text = text.charAt(0).toUpperCase() + text.slice(1);
return text;
}
function _parseErrorItem(item, listPos) {
var listItemTemplate = _.template(
'<li class="list-item"><span class="list-item-pos">Item <%= i %></span><%= content %></li>'
),
containerTemplate = _.template('<ul class="item"><%= content %></ul>'),
output = [];
_.each(item, function(value, key) {
var fieldTemplate = _.template(
'<li class="field"><span class="name"><%- name %></span><%= content %></li>'
),
plainValueTemplate = _.template('<span class="value"><%- value %></span>'),
plainValue,
listValue,
content;
if (_.isString(value)) {
plainValue = value;
} else if (_.isArray(value)) {
if (_.isString(value[0])) {
plainValue = value.join(' ');
} else {
listValue = _parseErrorList(value);
}
}
if (plainValue) {
content = plainValueTemplate({ value: plainValue });
} else if (listValue) {
content = listValue;
}
if (content) {
if (key.search(/[A-Z]/) != -1)
key =_camelCaseToVerbose(key);
if (key.search(/[\d_]/) != -1)
key =_underscoredToVerbose(key);
key = _capitalize(key);
output.push(fieldTemplate({
name: key,
content: content
}));
}
});
output = output.join('');
if (output) {
output = containerTemplate({ content: output });
if (listPos) {
output = listItemTemplate({
i: listPos,
content: output
});
}
}
return output;
}
function _parseErrorList(items) {
var containerTemplate = _.template('<ul class="list"><%= content %></ul>'),
output = [];
_.each(items, function(item, i) {
if (!_.isEmpty(item)) {
output.push(_parseErrorItem(item, i + 1));
}
});
output = output.join('');
if (output) {
output = containerTemplate({ content: output });
}
return output;
}
if (_.isArray(data)) {
return _parseErrorList(data);
} else {
return _parseErrorItem(data);
}
};
// Test example - remove it if you will use my gist in your code!
_.each([
{"detail": "Authentication is required."},
{"title": ["This field is required.", "Bad format."], "description": ["This field is required."]},
[{}, {"someKindOfField": ["This field is required."]}],
{"experience": [{}, {}, {"position_at_company": ["This field is required."],
"employer": ["This field is required."]}]}
], function(data) {
$('body').append(_.parseErrors(data));
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment