Angular: serialize/unserialize in JSON HttpRequest and HttpResponse object
Although I would recommend a Service Worker for Caching, the easiest way that I know is to clone the request/response and then get their information:
function serializeRequest(req: HttpRequest<any>): string {
const request = req.clone(); // Make a clone, useful for doing destructive things
return JSON.stringify({
headers: Object.fromEntries( // Just a helper to make this into an object, not really required but makes the output nicer
request.headers.keys.map( // Get all of the headers
(key: string) => [key, request.headers.getAll(key)] // Get all of the corresponding values for the headers
)
),
method: request.method, // The Request Method, e.g. GET, POST, DELETE
url: request.url, // The URL
params: Object.fromEntries( // Just a helper to make this into an object, not really required but makes the output nicer
request.headers.keys.map( // Get all of the headers
(key: string) => [key, request.headers.getAll(key)] // Get all of the corresponding values for the headers
)
), // The request parameters
withCredentials: request.withCredentials, // Whether credentials are being sent
respnseType: request.responseType, // The response type
body: request.serializeBody() // Serialize the body, all well and good since we are working on a clone
})
}
In a similar fashion we can serialize the response as well (assuming T
is JSON compatible, a fair assumption in an HTTP Request):
function serializeResponse(res: HttpResponse<any>): string {
const response = res.clone();
return JSON.stringify({
headers: Object.fromEntries( // Just a helper to make this into an object, not really required but makes the output nicer
response.headers.keys.map( // Get all of the headers
(key: string) => [key, response.headers.getAll(key)] // Get all of the corresponding values for the headers
)
),
status: response.status,
statusText: response.statusText,
url: response.url,
body: response // Serialize the body, all well and good since we are working on a clone
})
}
And then, since we saved all required information, deserialization is a walk in the park:
function deserializeRequest<T = any>(req: string): HttpRequest<T> {
const request = JSON.parse(req);
const headers = new HttpHeaders(request.headers);
const params = new HttpParams(); // Probably some way to make this a one-liner, but alas, there are no good docs
for(let parameter in request.params){
request.params[parameter].forEach((paramValue: string) => params.append(parameter, paramValue));
}
return new HttpRequest(request.method, request.url, request.body, {
headers,
params,
respnseType: request.respnseType,
withCredentials: request.withCredentials
});
}
function deserializeResponse<T = any>(res: string): HttpResponse<T> {
const response = JSON.parse(res);
const headers = new HttpHeaders(response.headers);
return new HttpRequest({
headers,
body: response.body,
status: response.status,
statusText: response.statusText,
url: response.url,
});
}
Playground of the whole thing (although, regrettably the angular types do not load correctly)
Note that I have not tested this in any environment, so this is provided AS-IS, and I am not sure how
expect
would handle twoHttpHeaders
/HttpParams
, especially since they may not have the exact same order.