Handling Request URL Parameters
# Handling Request URL Parameters
# Requirements Analysis
Remember the problem we left from the previous lesson. Let's look at this example again:
axios({
method: 'get',
url: '/base/get',
params: {
a: 1,
b: 2
}
})
2
3
4
5
6
7
8
We want the final request URL to be /base/get?a=1&b=2, so the server can parse the parameter data from the request URL. Essentially, we need to append the params object's keys and values to the url.
Let's look at some more complex examples.
# Array Parameter Values
axios({
method: 'get',
url: '/base/get',
params: {
foo: ['bar', 'baz']
}
})
2
3
4
5
6
7
The final request URL should be /base/get?foo[]=bar&foo[]=baz'.
# Object Parameter Values
axios({
method: 'get',
url: '/base/get',
params: {
foo: {
bar: 'baz'
}
}
})
2
3
4
5
6
7
8
9
The final request URL should be /base/get?foo=%7B%22bar%22:%22baz%22%7D, where the value after foo is the encoded result of {"bar":"baz"}.
# Date Parameter Values
const date = new Date()
axios({
method: 'get',
url: '/base/get',
params: {
date
}
})
2
3
4
5
6
7
8
9
The final request URL should be /base/get?date=2019-04-01T05:55:39.030Z, where the value after date is the result of date.toISOString().
# Special Character Support
For characters @, :, $, ,, , [, ], we allow them to appear in the URL and don't want them to be encoded.
axios({
method: 'get',
url: '/base/get',
params: {
foo: '@:$, '
}
})
2
3
4
5
6
7
The final request URL should be /base/get?foo=@:$+. Note that we convert spaces to +.
# Ignoring Null Values
For properties with null or undefined values, we don't add them to the URL parameters.
axios({
method: 'get',
url: '/base/get',
params: {
foo: 'bar',
baz: null
}
})
2
3
4
5
6
7
8
The final request URL should be /base/get?foo=bar.
# Discarding URL Hash Marks
axios({
method: 'get',
url: '/base/get#hash',
params: {
foo: 'bar'
}
})
2
3
4
5
6
7
The final request URL should be /base/get?foo=bar.
# Preserving Existing URL Parameters
axios({
method: 'get',
url: '/base/get?foo=bar',
params: {
bar: 'baz'
}
})
2
3
4
5
6
7
The final request URL should be /base/get?foo=bar&bar=baz.
# Implementing the buildURL Function
Based on our requirements analysis, we need to implement a utility function that appends params to the url. We want to manage utility functions and helper methods independently, so we create a helpers directory and create a url.ts file inside it for URL-related utility functions.
helpers/url.ts:
import { isDate, isObject } from './util'
function encode (val: string): string {
return encodeURIComponent(val)
.replace(/%40/g, '@')
.replace(/%3A/gi, ':')
.replace(/%24/g, '$')
.replace(/%2C/gi, ',')
.replace(/%20/g, '+')
.replace(/%5B/gi, '[')
.replace(/%5D/gi, ']')
}
export function bulidURL (url: string, params?: any) {
if (!params) {
return url
}
const parts: string[] = []
Object.keys(params).forEach((key) => {
let val = params[key]
if (val === null || typeof val === 'undefined') {
return
}
let values: string[]
if (Array.isArray(val)) {
values = val
key += '[]'
} else {
values = [val]
}
values.forEach((val) => {
if (isDate(val)) {
val = val.toISOString()
} else if (isObject(val)) {
val = JSON.stringify(val)
}
parts.push(`${encode(key)}=${encode(val)}`)
})
})
let serializedParams = parts.join('&')
if (serializedParams) {
const markIndex = url.indexOf('#')
if (markIndex !== -1) {
url = url.slice(0, markIndex)
}
url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams
}
return url
}
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
helpers/util.ts:
const toString = Object.prototype.toString
export function isDate (val: any): val is Date {
return toString.call(val) === '[object Date]'
}
export function isObject (val: any): val is Object {
return val !== null && typeof val === 'object'
}
2
3
4
5
6
7
8
9
10
# Implementing URL Parameter Processing Logic
We've implemented the buildURL function. Now let's use it to implement the URL parameter processing logic.
Add the following code in index.ts:
function axios (config: AxiosRequestConfig): void {
processConfig(config)
xhr(config)
}
function processConfig (config: AxiosRequestConfig): void {
config.url = transformUrl(config)
}
function transformUrl (config: AxiosRequestConfig): string {
const { url, params } = config
return bulidURL(url, params)
}
2
3
4
5
6
7
8
9
10
11
12
13
Before executing the xhr function, we first execute the processConfig method to process the data in config. Besides handling url and params, we'll process other properties in the future.
Inside processConfig, we modify config.url by executing the transformUrl function, which internally calls buildURL.
With that, the URL parameter processing logic is complete. Next, let's write a demo.
# Writing the Demo
Create a base directory under examples, and create index.html inside:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Base example</title>
</head>
<body>
<script src="/__build__/base.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: '/base/get',
params: {
foo: ['bar', 'baz']
}
})
axios({
method: 'get',
url: '/base/get',
params: {
foo: {
bar: 'baz'
}
}
})
const date = new Date()
axios({
method: 'get',
url: '/base/get',
params: {
date
}
})
axios({
method: 'get',
url: '/base/get',
params: {
foo: '@:$, '
}
})
axios({
method: 'get',
url: '/base/get',
params: {
foo: 'bar',
baz: null
}
})
axios({
method: 'get',
url: '/base/get#hash',
params: {
foo: 'bar'
}
})
axios({
method: 'get',
url: '/base/get?foo=bar',
params: {
bar: 'baz'
}
})
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Then add a new route in server.js:
router.get('/base/get', function(req, res) {
res.json(req.query)
})
2
3
Run npm run dev in the terminal, then open Chrome and visit http://localhost:8080/ to access our demo. Click into the Base directory, and through the network tab in Developer Tools, you can see multiple requests were sent successfully, and their final URLs have the request parameters properly appended.
With that, we've finished implementing request URL parameter handling. In the next section, we'll handle request body data.