Error Handling
# Error Handling
# Requirements Analysis
In the previous chapter, we implemented the core features of ts-axios, but so far we've only handled the happy path for receiving requests and haven't considered any error handling. This is far from sufficient for a robust program, so in this chapter we need to handle various AJAX error scenarios.
We also want the program to be able to catch these errors for further processing.
axios({
method: 'get',
url: '/error/get'
}).then((res) => {
console.log(res)
}).catch((e) => {
console.log(e)
})
2
3
4
5
6
7
8
If any error occurs during the request, we can catch it in the reject callback function.
We've categorized the errors into several types. Let's handle each one separately.
# Handling Network Errors
When a network error occurs (e.g., no connectivity), sending a request triggers the error event on the XMLHttpRequest object instance. We can capture this type of error in the onerror (opens new window) event callback.
We add the following code to the xhr function:
request.onerror = function handleError() {
reject(new Error('Network Error'))
}
2
3
# Handling Timeout Errors
We can set a timeout (opens new window) for a request -- if the request doesn't receive a response within the specified time, it automatically terminates and triggers the timeout event.
The default timeout is 0, meaning no timeout. So we first need to allow configuring the timeout:
export interface AxiosRequestConfig {
// ...
timeout?: number
}
2
3
4
Then add the following code to the xhr function:
const { /*...*/ timeout } = config
if (timeout) {
request.timeout = timeout
}
request.ontimeout = function handleTimeout() {
reject(new Error(`Timeout of ${timeout} ms exceeded`))
}
2
3
4
5
6
7
8
9
# Handling Non-2xx Status Codes
For a normal request, the HTTP status code is typically between 200 and 300. For status codes outside this range, we treat them as errors.
request.onreadystatechange = function handleLoad() {
if (request.readyState !== 4) {
return
}
if (request.status === 0) {
return
}
const responseHeaders = parseHeaders(request.getAllResponseHeaders())
const responseData =
responseType && responseType !== 'text' ? request.response : request.responseText
const response: AxiosResponse = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config,
request
}
handleResponse(response)
}
function handleResponse(response: AxiosResponse) {
if (response.status >= 200 && response.status < 300) {
resolve(response)
} else {
reject(new Error(`Request failed with status code ${response.status}`))
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
In the onreadystatechange callback, we added a check for request.status (opens new window) because when a network error or timeout error occurs, this value is 0.
Then in the handleResponse function, we check request.status again -- if it's a 2xx status code, we consider it a normal request; otherwise we throw an error.
# Writing the Demo
Create an error directory under examples, and create index.html inside:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error example</title>
</head>
<body>
<script src="/__build__/error.js"></script>
</body>
</html>
2
3
4
5
6
7
8
9
10
Then create app.ts as the entry file:
import axios from '../../src/index'
axios({
method: 'get',
url: '/error/get1'
}).then((res) => {
console.log(res)
}).catch((e) => {
console.log(e)
})
axios({
method: 'get',
url: '/error/get'
}).then((res) => {
console.log(res)
}).catch((e) => {
console.log(e)
})
setTimeout(() => {
axios({
method: 'get',
url: '/error/get'
}).then((res) => {
console.log(res)
}).catch((e) => {
console.log(e)
})
}, 5000)
axios({
method: 'get',
url: '/error/timeout',
timeout: 2000
}).then((res) => {
console.log(res)
}).catch((e) => {
console.log(e.message)
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Then add new route handlers in server.js:
router.get('/error/get', function(req, res) {
if (Math.random() > 0.5) {
res.json({
msg: `hello world`
})
} else {
res.status(500)
res.end()
}
})
router.get('/error/timeout', function(req, res) {
setTimeout(() => {
res.json({
msg: `hello world`
})
}, 3000)
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Run npm run dev in the terminal, then open Chrome and visit http://localhost:8080/. Click into the Error directory, and through the network tab in Developer Tools you can see the different error scenarios.
With this, we've handled various error types and thrown them to the application layer for further processing. However, our errors are just simple Error instances with only text messages -- they don't include information about which request failed, the request configuration, the response object, etc. In the next lesson, we'll enhance the error information.