Handling Request Body Data
# Handling Request Body Data
# Requirements Analysis
We send requests by executing the send method on an XMLHttpRequest object instance and set the request body data through this method's parameter. You can check the supported parameter types on MDN (opens new window).
We find that the send method supports Document and BodyInit types. BodyInit includes Blob, BufferSource, FormData, URLSearchParams, ReadableStream, and USVString. When there's no data, we can pass null.
However, the most common scenario is passing a plain object to the server, for example:
axios({
method: 'post',
url: '/base/post',
data: {
a: 1,
b: 2
}
})
2
3
4
5
6
7
8
In this case, data cannot be passed directly to the send function -- we need to convert it to a JSON string.
# Implementing the transformRequest Function
Based on the requirements, we need to implement a utility function to transform the data in the request. We create a new file data.ts in the helpers directory.
helpers/data.ts:
import { isPlainObject } from './util'
export function transformRequest (data: any): any {
if (isPlainObject(data)) {
return JSON.stringify(data)
}
return data
}
2
3
4
5
6
7
8
helpers/util.js:
export function isPlainObject (val: any): val is Object {
return toString.call(val) === '[object Object]'
}
2
3
Why do we use isPlainObject instead of the previous isObject? Because with isObject's check, types like FormData and ArrayBuffer would also return true, but we don't need to process those data types. isPlainObject only matches plain JSON objects that we define ourselves.
helpers/url.ts:
if (isDate(val)) {
val = val.toISOString()
} else if (isPlainObject(val)) {
val = JSON.stringify(val)
}
2
3
4
5
For the parameter value checks from the previous lesson, we should also use isPlainObject for correctness.
helpers/util.js
// export function isObject (val: any): val is Object {
// return val !== null && typeof val === 'object'
// }
2
3
Since isObject is no longer used, we'll comment it out for now.
# Implementing Request Body Processing Logic
index.ts:
import { transformRequest } from './helpers/data'
```typescript
function processConfig (config: AxiosRequestConfig): void {
config.url = transformURL(config)
config.data = transformRequestData(config)
}
function transformRequestData (config: AxiosRequestConfig): any {
return transformRequest(config.data)
}
2
3
4
5
6
7
8
9
10
11
We defined a transformRequestData function to transform the request body data, which internally calls the transformRequest method we just implemented.
Then we added this logic inside processConfig, processing config's data after handling the URL.
# Writing the Demo
axios({
method: 'post',
url: '/base/post',
data: {
a: 1,
b: 2
}
})
const arr = new Int32Array([21, 31])
axios({
method: 'post',
url: '/base/buffer',
data: arr
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
We add 2 code snippets to examples/base/app.ts. The first post request's data is a plain object, and the second request's data is an Int32Array type that can be passed directly to the XMLHttpRequest object's send method.
router.post('/base/post', function(req, res) {
res.json(req.body)
})
router.post('/base/buffer', function(req, res) {
let msg = []
req.on('data', (chunk) => {
if (chunk) {
msg.push(chunk)
}
})
req.on('end', () => {
let buf = Buffer.concat(msg)
res.json(buf.toJSON())
})
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
We add 2 routes to examples/server.js for these two request types, each returning the data sent in the request.
When we open the browser and run the demo, we find that the /base/buffer request can retrieve data, but the base/post request's response returns an empty object. Why?
The reason is that although we converted the plain object data to a JSON string when executing the send method, the request header's Content-Type is text/plain;charset=UTF-8, which causes the server to fail to properly parse the request body data.
Now that we understand this issue, in the next lesson we'll implement request header handling.