I think I've found a way to do what I want
import axios, { AxiosResponse } from "axios";
class BadResponseFormatError extends Error {
constructor (public response: AxiosResponse) {
super("Malformed response");
}
}
axios.interceptors.response.use(
(response: AxiosResponse) => {
if (response.headers["content-type"] !== "application/json") {
throw new BadResponseFormatError(response);
}
try {
response.data = JSON.parse(response.data);
return response;
} catch {
throw new BadResponseFormatError(response);
}
}
)
axios.get('http://cataas.com/cat?html=true', {responseType: "json", transformResponse: (body) => body})
.then((res) => console.log(`Got response with data ${JSON.stringify(res.data)}`))
.catch((err) => {
// This could also be moved to a response interceptor,
// I just did it here for the sake of demonstration
if (err instanceof BadResponseFormatError) {
console.error(`Got a bad format response with status code ${err.response.status}: ${err.response.data}`)
} else {
console.error(`Got some other error: ${err}`)
}
}
)
A brief summary of what's going on
- I'm using
transformResponsewith a value of(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 then delay the actual parse to the response interceptor, which allows me to error handle the parse manually.
- From there, I can create a custom exception that contains the original response, which I then use in my error handling.
I think I've found a way to do what I want
import axios, { AxiosResponse } from "axios";
class BadResponseFormatError extends Error {
constructor (public response: AxiosResponse) {
super("Malformed response");
}
}
axios.interceptors.response.use(
(response: AxiosResponse) => {
if (response.headers["content-type"] !== "application/json") {
throw new BadResponseFormatError(response);
}
try {
response.data = JSON.parse(response.data);
return response;
} catch {
throw new BadResponseFormatError(response);
}
}
)
axios.get('http://cataas.com/cat?html=true', {responseType: "json", transformResponse: (body) => body})
.then((res) => console.log(`Got response with data ${JSON.stringify(res.data)}`))
.catch((err) => {
// This could also be moved to a response interceptor,
// I just did it here for the sake of demonstration
if (err instanceof BadResponseFormatError) {
console.error(`Got a bad format response with status code ${err.response.status}: ${err.response.data}`)
} else {
console.error(`Got some other error: ${err}`)
}
}
)
A brief summary of what's going on
- I'm using
transformResponsewith a value of(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 then delay the actual parse to the response interceptor, which allows me to error handle the parse manually.
- From there, I can create a custom exception that contains the original response, which I then use in my error handling.
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:
const a = { x: 10}
Some people would call a a JSON object, but strictly speaking it is not. The JSON representation of a is the following string:
{ "x": 10 }
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
datais a Javascript object, and "text/html" ifdatais an HTML response.
Here is your code showing the content-type of the server response explicitly.
axios.get('http://cataas.com/cat?html=true')
.then(response => {
console.log("Example of an API returning an HTML response")
const contentType = response.headers["content-type"];
const data = response.data;
console.log("Type of response data is:", contentType)
console.log("Because it is a long string, I am just going to show a few characters of it:", data.slice(0, 40))
})
.catch((err) => console.log(`Error: ${err}`))
axios.get('https://dummyjson.com/products/1')
.then(response => {
console.log("Example of an API returning an JSON response")
const contentType = response.headers["content-type"];
const data = response.data;
console.log("Type of response data is:", contentType)
console.log("Because it is a small object, I am going to show it all:", data)
})
.catch((err) => console.log(`Error: ${err}`))
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.3.4/axios.min.js" integrity="sha512-LUKzDoJKOLqnxGWWIBM4lzRBlxcva2ZTztO8bTcWPmDSpkErWx0bSP4pdsjNH8kiHAUPaT06UXcb+vOEZH+HpQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
The http://cataas.com/cat?html=true API returns an HTML string
Axios faithfully gives you that string in the data property.
<!DOCTYPE html>
<html lang="en">
<header>
<meta charset="utf-8">
</header>
<body>
<img alt="ltBmKwnyGcagdHo3" src="/cat/ltBmKwnyGcagdHo3">
</body>
</html>
The https://dummyjson.com/products/1 API returns a JSON string to Axios
Axios automatically converts that JSON string into a Javascript object for you.
{"id":1,"title":"iPhone 9","description":"An apple mobile which is nothing like apple","price":549,"discountPercentage":12.96,"rating":4.69,"stock":94,"brand":"Apple","category":"smartphones","thumbnail":"https://i.dummyjson.com/data/products/1/thumbnail.jpg","images":["https://i.dummyjson.com/data/products/1/1.jpg","https://i.dummyjson.com/data/products/1/2.jpg","https://i.dummyjson.com/data/products/1/3.jpg","https://i.dummyjson.com/data/products/1/4.jpg","https://i.dummyjson.com/data/products/1/thumbnail.jpg"]}
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.dataas a Javascript objectIf it begins with
text/html, despite you having requested a JSON, then something has gone wrong. You could readresponse.dataas 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 whether response.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.
Videos
My json file "testing.json" is in the public folder, the line I have is
axios.get('testing.json').then(.....but it can't read the file for some reason. I uploaded the exact same json file to a website and put the url in the get request, and it worked fine, so the file isn't the issue. I think it's a problem with how I'm calling the file with axios.get but I've looked at other posts on various online forums and can't figure it out. Does axios not work with local files?
» npm install axios-get-json-response
In Axios responses are already served as javascript object, no need to parse, simply get response and access data.
Assuming the response from the server looks like this:
{"token": "1234567890"}
Then in Axios you can access it like this:
console.log( response.data.token )
obj.data(in data there is property children which is Array) is Object not Array, I think in this case better change default state, and create one field for kind (String) and one for data (Array), like so
class TableUser extends React.Component {
constructor(props) {
super(props);
this.state = {
kind: '',
data: []
};
}
componentDidMount(){
axios
.get('https://www.reddit.com/r/reactjs.json')
.then(({ data })=> {
this.setState({
kind: data.kind,
data: data.data.children
});
})
.catch((err)=> {})
}
render() {
const child = this.state.data.map((el, index) => {
return <div key={index}>
<p>Title - { el.data.title }</p>
<p>Author - { el.data.author }</p>
</div>
});
return <div>
<p>{ this.state.kind }</p>
<div>{ child }</div>
</div>;
}
}
ReactDOM.render(
<TableUser />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.js"></script>
<div id="container"></div>
data.json
{ "email":"[email protected]", "password":"1234" }
get_data.js
import React, { Component } from 'react';
import './css.css'
import Logout from './logout';
import axios from 'axios';
import { Redirect } from 'react-router-dom';
class Login extends Component {
constructor(props){
super();
this.state=({
valid:false,
email1:'',
pass1:'',
msg:'valid'
})
this.check = this.check.bind(this);
}
check()
{
axios.get('http://127.0.0.1:8887/src/component/data.json')
.then((response) => {
this.setState({
email1:response.data.email,
pass1:response.data.password
})
})
.catch((err)=> {})
if(this.email.value === this.state.email1 && this.password.value === this.state.pass1)
{
this.setState({
valid:true
})
}
else{
this.setState({
msg:"invalid number"
})
}
}
render() {
return (
<div className="card-m">
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input ref={(email1 => (this.email=email1))} type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" />
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input ref={(pass => (this.password=pass))} type="password" class="form-control" id="exampleInputPassword1" />
</div>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1" />
<label class="form-check-label" for="exampleCheck1">Check me out</label>
</div>
<button onClick={this.check} type="submit" class="btn btn-primary">Submit</button>
{ this.state.valid &&
<Redirect to="/logout" />
}
</div>
);
}
}
export default Login;
» npm install axios