I'm using angular 4 with a .net core web api and returning a 400 response in case of model validation.
This is the method on the controller
[HttpPut("crea-utente")]
[Authorize(CfgAutorizzazioni.AutSistema.Utenti.UPDATE)]
[ProducesResponseType(typeof(Guid), 200)]
[ProducesResponseType(typeof(DgkErrorResult), 400)]
public async Task<Guid> CreaUtente([FromBody] CreaUtenteDTO dto)
{
return await _mediator.Send(new UtenteCrea.Request(dto, ClienteCodice, CodiceApplicazione, ConnessioneId));
}
this is the client generated from the typescript client generator
creaUtente(dto: CreaUtenteDTO | null): Observable<string> {
let url_ = this.baseUrl + "/api/UtenteLocale/crea-utente";
url_ = url_.replace(/[?&]$/, "");
const content_ = JSON.stringify(dto);
let options_ : any = {
body: content_,
observe: "response",
responseType: "blob",
headers: new HttpHeaders({
"Content-Type": "application/json",
"Accept": "application/json"
})
};
return this.http.request("put", url_, options_).flatMap((response_ : any) => {
return this.processCreaUtente(response_);
}).catch((response_: any) => {
if (response_ instanceof HttpResponse) {
try {
return this.processCreaUtente(response_);
} catch (e) {
return <Observable<string>><any>Observable.throw(e);
}
} else
return <Observable<string>><any>Observable.throw(response_);
});
}
protected processCreaUtente(response: HttpResponse<Blob>): Observable<string> {
const status = response.status;
let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }};
if (status === 200) {
return blobToText(response.body).flatMap(_responseText => {
let result200: any = null;
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
result200 = resultData200 !== undefined ? resultData200 : <any>null;
return Observable.of(result200);
});
} else if (status === 400) {
return blobToText(response.body).flatMap(_responseText => {
let result400: any = null;
let resultData400 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
result400 = resultData400 ? DgkErrorResult.fromJS(resultData400) : <any>null;
return throwException("A server error occurred.", status, _responseText, _headers, result400);
});
} else if (status !== 200 && status !== 204) {
return blobToText(response.body).flatMap(_responseText => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Observable.of<string>(<any>null);
}
But in case of model validation error the response is not an HttpResponse but rather an HttpErrorResponse so the processCreaUtente is not invoked in the catch.
So something is wrong in my configuration but I can't figure out what. Any suggesttions will be much appreciated. Thanks.
Luca
I have the same problem, but the other way around.
My generated typescript code looks like this:
test(input: string): Observable<any> {
let url_ = this.baseUrl + "/api/Home/test/{input}";
if (input === undefined || input === null)
throw new Error("The parameter 'input' must be defined.");
url_ = url_.replace("{input}", encodeURIComponent("" + input));
url_ = url_.replace(/[?&]$/, "");
let options_ : any = {
observe: "response",
responseType: "blob",
headers: new HttpHeaders({
"Content-Type": "application/json",
"Accept": "application/json"
})
};
return this.http.request("get", url_, options_).flatMap((response_ : any) => {
return this.processTest(response_);
}).catch((response_: any) => {
if (response_ instanceof HttpResponse) {
try {
return this.processTest(response_);
} catch (e) {
return <Observable<any>><any>Observable.throw(e);
}
} else
return <Observable<any>><any>Observable.throw(response_);
});
}
...
The response_ object in the catch method is of type HttpErrorResponseand never gets transformed by the processTest() method.
I found one possible workaround: (https://github.com/angular/angular/issues/18680#issuecomment-339726251)
Use a HttpInterceptor to transform the HttpErrorResponse to HttpResponse. But with this workaround I ran into another problem (https://github.com/RSuter/NSwag/issues/1070).
There was actually an mistyping in my code, I changedit. The code generated handles HttpResponse and not HttpErrorResponse, the edit was mine manually. So we have the same problem.
so the only problem is
if (response_ instanceof HttpResponse) {
?
What would be the correct code here?
I made some tests and this would get me the actual error, but I'm not an expert so maybe this is completely wrong.
if (response_ instanceof HttpErrorResponse) {
try {
const httpResponse = new HttpResponse<Blob>({body: response_.error, headers: response_.headers, status: response_.status, statusText: response_.statusText, url: response_.url});
return this.processTest(httpResponse);
} catch (e) {
return <Observable<MyDTO | null>><any>Observable.throw(e);
}
} else
return <Observable<MyDTO | null>><any>Observable.throw(response_);
In my case the response_.error of the HttpErrorResult is a blob with the json of my error dto.
I hope I was clear enough.
Luca
Is this fixed with this PR? https://github.com/RSuter/NSwag/pull/1071
@llusetti it's the same problem that I'm having and it should work for you because HttpErrorResponse extends from HttpReponseBase
class HttpErrorResponse extends HttpResponseBase implements Error {
constructor(init: {...})
get name: 'HttpErrorResponse'
.......
I'll try replacing just the liquid templates and let you know. Thanks
I've updated the templates, please retest with the latest CI artifacts: https://ci.appveyor.com/project/rsuter/nswag-25x6o/build/artifacts
Seems to work with the latest version 11.12.11!
Thx :)
Thanks for reporting back.
Most helpful comment
I made some tests and this would get me the actual error, but I'm not an expert so maybe this is completely wrong.
In my case the response_.error of the HttpErrorResult is a blob with the json of my error dto.
I hope I was clear enough.
Luca