In .NET Web API when any DataAnnotation attribute validation failed, it returns HTTP status code: 400 with the response as below:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-57b63f3ea418de93f36e991b5d8d2567-29a28274787dd62d-00",
"errors": {
"": [
"A non-empty request body is required."
],
"request": [
"The request field is required."
]
}
}
This is a ProblemDetails
class as per MSDN.
Can someone let me know how to parse the errors
part into an array of strings?
For example:
errors
contain an array, whose item is a key-value pair.
{
"errors": {
"Field 1 Name": [
"The request field is required."
],
"Field 2 Name": [
"The request field is required."
],
.
.
.
"Field nth Name": [
"The request field is required."
]
}
How can I get these errors into the collection to show on UI for users? I want to show it in toast as:
"Key : Value"
"Field 1 Name : The request field is required."
Use the catchError
rxjs operator to handle the response with the error status code.
Based on your sample API response, I extract the value from the error
part, and convert it from the key-value pair (which is key: string
, value: string[]
), flatten the value
to an array of objects with { field: string, error: string }
type.
And return the error Observable as { status: number, errorText: string, response: any }
type.
Service
import { catchError, throwError } from 'rxjs';
submit(body: any): Observable<any> {
// In real environment this is how you post request, get response and handle error response
return this.http
.post(API_URL, body)
.pipe(catchError((err) => this.handleError(err)));
}
handleError(err: any): Observable<any> {
let handleErrResponse = {
status: err.status,
errorText: err.message || err.errorMessage || err.title,
response: err,
};
if (err.status == 400) {
let errors = Object.entries(err.errors).reduce(
(acc, cur: [string, string[]]) => {
for (let err of cur[1]) {
acc.push({
field: cur[0],
error: err,
});
}
return acc;
},
[] as { field: string; error: string }[]
);
handleErrResponse.response = errors;
}
return throwError(() => handleErrResponse);
}
When the Observable
is returned, trace whether the status
is 400. If true, then you pass the formatted response
to display the error messages as toast.
Component
onSubmit() {
let body = {};
this.service.submit(body).subscribe({
next: (response) => {
// Success
},
error: (err) => {
if (err.status == 400) {
this.hasError = true;
this.errors = err.response;
// Use err.response to display in toast
}
},
});
}
In my demo, I just display the formatted error response as an HTML template to prove the concept works.
<div *ngIf="hasError">
<div *ngFor="let err of errors">
{{ err.field }} : {{ err.error }}
</div>
</div>