While using Angular HttpClient
post
, it seems the default is to treat the response as JSON string. This caused error even for 201 response when the response body is empty as empty string ""
fails JSON.parse()
.
The solution is to specify responseType: "text"
as additional option, so that empty body is not treated as error.
However, the API endpoint does return error description in JSON when the request fails (i.e. empty on success, JSON on error).
How do you construct the HttpClient
post
so that I can get the error message object back when it fails and success does not count as error?
e.g.:
.subscribe(() => {
// do something for success, no return object as the body is empty
, error => {
// do something with the returned error object
// right now success is still counted as an error due to the issue above
}
);
A server that returns response code 200
or 201
with an empty response body and Content-Type
specified as application/json
is misconfigured, since an empty string is not valid JSON.
As the OP indicated, specifying responseType: "text"
fixes the error, since the empty body is not parsed as JSON.
A workaround is to proceed with responseType: "text"
and check if the response body is empty. If the response body is not empty, then call JSON.parse(response)
.
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
type HttpOptions = {
headers?: HttpHeaders | { [header: string]: string | string[]; };
observe?: "body"; params?: HttpParams | { [param: string]: string | string[]; };
reportProgress?: boolean; responseType?: "json" /* or "text" as "json" */;
withCredentials?: boolean;
}
let get_http_options_text = (): HttpOptions => {
return {
headers: {'Content-Type': 'text/plain'},
observe: "body",
responseType: "text" as "json", // @see https://github.com/angular/angular/issues/18586
withCredentials: true
}
}
@Injectable()
export class MyHttpService {
constructor(private http: HttpClient) {}
public post_body_as_string(url: string, body: any, http_params: HttpParams = null):
Observable<any> {
let options = get_http_options_text();
if (http_params != null) {
options['params'] = http_params;
}
return this.http.post<string>(url, body, options).pipe(
map(response => {
if (response !== '') {
return JSON.parse(response);
} else {
return {}
}
})
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With