I’m evaluating Axios and one thing I can’t seem to figure out how to enforce that a response is JSON. From what I’ve gathered, Axios will automatically parse the JSON for us based on the content type (https://stackoverflow.com/a/65976510/1103734). However, I was hoping to actually enforce that the response is JSON (e.g. if my nginx proxy returns HTML due to a downstream error, I would want to handle that).
I noticed that the Axios request config has a responseType
property, but as near as I can tell, this is not used to actually enforce an expected type is returned. Here’s an example snippet that demonstrates what I’m talking about
axios.get('http://cataas.com/cat?html=true', {responseType: "json"})
.then(res => console.log(`Response:n ${res.data}`))
.catch((err) => console.log(`Error: ${err}`))
Output:
Response:
<!DOCTYPE html>
<html lang="en">
<header>
<meta charset="utf-8">
</header>
<body>
<img alt="GRxZb4kUHleQ3LhC" src="/cat/GRxZb4kUHleQ3LhC">
</body>
</html>
The best thing I can find is to put JSON.parse
in the transformResponse
property, but this means that if there’s an error in parsing a response with a bad status code, I will lose that status code information in my catch
.
axios.get('http://cataas.com/cat?html=true', {responseType: "json", transformResponse: JSON.parse})
.then(res => console.log(`Responsen ${res.data}`))
.catch((err) => console.log(`Error: ${err}`))
Output (obviously, SyntaxError
does not contain any information about the response):
Error: SyntaxError: Unexpected token < in JSON at position 17
Is there a nice way to achieve what I want?
2
Answers
I think I've found a way to do what I want
A brief summary of what's going on
transformResponse
doing(body) => body
, as presented in this answer. This allows the response interceptor to actually get at the textual response data. This was the key to make this work.I think there is some confusion about the term "JSON"
I think what you mean is that you want the result from Axios to be a Javascript object, not a JSON string. The confusion is common because we often call Javascript objects "JSON objects" as a slang term.
If you type the following into the console, the resulting value of
a
will be a Javascript object:Some people would call
a
a JSON object, but strictly speaking it is not. The JSON representation ofa
is the following string:What Axios returns to you_ not a JSON string, but a Javascript object
This contains various pieces of information, in different properties of the object. Important to us here are:
The "data" property, which may be a string containing HTML, or a Javascript object, or something else.
Within the "headers" property, the "content-type" subproperty. This will begin with "application/json" if
data
is a Javascript object, and "text/html" ifdata
is an HTML response.Here is your code showing the content-type of the server response explicitly.
The
http://cataas.com/cat?html=true
API returns an HTML stringAxios faithfully gives you that string in the
data
property.The
https://dummyjson.com/products/1
API returns a JSON string to AxiosAxios automatically converts that JSON string into a Javascript object for you.
One way to achieve what you want:
Read
response.headers["content-type"]
If it begins with
application/json
, then you are in luck: just treatresponse.data
as a Javascript objectIf it begins with
text/html
, despite you having requested a JSON, then something has gone wrong. You could readresponse.data
as HTML, and look for whether the server said anything helpful.I don’t like the idea of wrapping everything in a
try
/catch
, and picking up a failed JSON.parse. We are already being given information on whetherresponse.data
is an object or not, so let’s use that.You could even write a wrapper for Axios
That could do the above, so you only have to write the code once.