VDone Demo VDone Demo
Home
  • Articles

    • JavaScript
  • Study Notes

    • JavaScript Tutorial
    • Professional JavaScript
    • ES6 Tutorial
    • Vue
    • React
    • TypeScript: Build Axios from Scratch
    • Git
    • TypeScript
    • JS Design Patterns
  • HTML
  • CSS
  • Technical Docs
  • GitHub Tips
  • Node.js
  • Blog Setup
  • Learning
  • Interviews
  • Miscellaneous
  • Practical Tips
  • Friends
About
Bookmarks
  • Categories
  • Tags
  • Archives
GitHub (opens new window)

Nikolay Tuzov

Backend Developer
Home
  • Articles

    • JavaScript
  • Study Notes

    • JavaScript Tutorial
    • Professional JavaScript
    • ES6 Tutorial
    • Vue
    • React
    • TypeScript: Build Axios from Scratch
    • Git
    • TypeScript
    • JS Design Patterns
  • HTML
  • CSS
  • Technical Docs
  • GitHub Tips
  • Node.js
  • Blog Setup
  • Learning
  • Interviews
  • Miscellaneous
  • Practical Tips
  • Friends
About
Bookmarks
  • Categories
  • Tags
  • Archives
GitHub (opens new window)
  • 初识 TypeScript

  • TypeScript 常用语法

  • ts-axios 项目初始化

    • Requirements Analysis
    • Initializing the Project
    • Writing Basic Request Code
      • Creating the Entry File
        • Compilation Configuration File tsconfig.json
        • Defining the AxiosRequestConfig Interface Type
      • Sending Requests with XMLHttpRequest
        • Importing the xhr Module
      • Writing the Demo
        • Installing Dependencies
        • Writing the webpack Configuration File
        • Writing the Server File
        • Writing the Demo Code
        • Running the Demo
  • ts-axios 基础功能实现

  • ts-axios 异常情况处理

  • ts-axios 接口扩展

  • ts-axios 拦截器实现

  • ts-axios 配置化实现

  • ts-axios 取消功能实现

  • ts-axios 更多功能实现

  • ts-axios 单元测试

  • ts-axios 部署与发布

  • 《TypeScript 从零实现 axios》
  • ts-axios 项目初始化
HuangYi
2020-01-05
Contents

Writing Basic Request Code

# Writing Basic Request Code

In this lesson, we start writing the ts-axios library. Our goal is to implement simple request sending functionality -- the client sends a request to the server via the XMLHttpRequest object, and the server can receive and respond to the request.

We'll implement the most basic operation of axios, sending a request by passing in an object, like this:

axios({
  method: 'get',
  url: '/simple/get',
  params: {
    a: 1,
    b: 2
  }
})
1
2
3
4
5
6
7
8

# Creating the Entry File

We delete the files in the src directory and first create an index.ts file as the entry file for the entire library. Then we define an axios method and export it:


function axios(config) {

}

export default axios

1
2
3
4
5
6
7

Here the TypeScript compiler will flag errors: an implicit any error on the config declaration, and an empty code block. The empty code block is straightforward. The first error occurs because we set strict to true in the TypeScript compilation config.

# Compilation Configuration File tsconfig.json

The tsconfig.json file specifies the root files and compilation options for the project. For detailed learning, I recommend visiting the official site (opens new window) for a systematic study.

When we covered TypeScript basics earlier, we ran the tsc command to compile TypeScript files. The compiler looks for the tsconfig.json file starting from the current directory and uses it for compilation options.

Let's look at the tsconfig.json file -- it contains many compilation settings. We set strict to true, which is equivalent to enabling all strict type checking options. Enabling --strict is equivalent to enabling --noImplicitAny, --noImplicitThis, --alwaysStrict, --strictNullChecks, --strictFunctionTypes, and --strictPropertyInitialization.

We mentioned --strictNullChecks when covering TypeScript basics. For other compilation options, I recommend checking the official documentation (opens new window) as a reference manual.

# Defining the AxiosRequestConfig Interface Type

Next, we need to define an interface type for the config parameter. We create a types directory with an index.ts file inside it, serving as the shared type definition file for the project.

Let's define the AxiosRequestConfig interface type:

export interface AxiosRequestConfig {
  url: string
  method?: string
  data?: any
  params?: any
}
1
2
3
4
5
6

Here, url is the request address and is required; the rest are optional properties. method is the HTTP method of the request; data is the data for post, patch, and similar request types, placed in the request body; params is the data for get, head, and similar request types, appended to the URL's query string.

To ensure method only accepts valid strings, we define a string literal type Method:

export type Method = 'get' | 'GET'
  | 'delete' | 'Delete'
  | 'head' | 'HEAD'
  | 'options' | 'OPTIONS'
  | 'post' | 'POST'
  | 'put' | 'PUT'
  | 'patch' | 'PATCH'
1
2
3
4
5
6
7

Then we change the method property type in AxiosRequestConfig to this string literal type:

export interface AxiosRequestConfig {
  url: string
  method?: Method
  data?: any
  params?: any
}
1
2
3
4
5
6

Back in index.ts, we import the AxiosRequestConfig type as the parameter type for config:

import { AxiosRequestConfig } from './types'

function axios(config: AxiosRequestConfig) {
}

export default axios
1
2
3
4
5
6

Next, let's implement the logic inside this function body -- sending the request.

# Sending Requests with XMLHttpRequest

We don't want to implement the request sending logic directly in index.ts. Following modular programming principles, we extract this functionality into a separate module.

So we create an xhr.ts file in the src directory. We export an xhr method that accepts a config parameter of type AxiosRequestConfig.

import { AxiosRequestConfig } from './types'

export default function xhr(config: AxiosRequestConfig) {
}
1
2
3
4

Next, let's implement the function body logic:

export default function xhr(config: AxiosRequestConfig): void {
  const { data = null, url, method = 'get' } = config

  const request = new XMLHttpRequest()

  request.open(method.toUpperCase(), url, true)

  request.send(data)
}
1
2
3
4
5
6
7
8
9

First, we use destructuring assignment to extract the corresponding property values from config and assign them to variables, with some default values defined since some properties in the AxiosRequestConfig interface are optional.

Then we instantiate an XMLHttpRequest object, call its open method with the corresponding parameters, and finally call the send method to send the request.

For learning about XMLHttpRequest, I recommend studying its properties and methods systematically on MDN (opens new window) as a reference, since we may frequently consult this documentation during development.

# Importing the xhr Module

After writing the xhr module, we need to import it in index.ts:

import { AxiosRequestConfig } from './types'
import xhr from './xhr'

function axios(config: AxiosRequestConfig): void {
  xhr(config)
}

export default axios
1
2
3
4
5
6
7
8

With that, our basic request sending code is complete. Next, let's write a small demo to use our axios library to send requests.

# Writing the Demo

We'll use Node.js's express (opens new window) library to run our demo, and webpack (opens new window) as the build tool.

# Installing Dependencies

First, let's install the dependencies needed for writing the demo:

"webpack": "^4.28.4",
"webpack-dev-middleware": "^3.5.0",
"webpack-hot-middleware": "^2.24.3",
"ts-loader": "^5.3.3",
"tslint-loader": "^3.5.4",
"express": "^4.16.4",
"body-parser": "^1.18.3"
1
2
3
4
5
6
7

Here, webpack is the bundling tool, webpack-dev-middleware and webpack-hot-middleware are two express middleware for webpack, ts-loader and tslint-loader are TypeScript-related loaders for webpack, express is the Node.js server framework, and body-parser is an express middleware for parsing body data.

# Writing the webpack Configuration File

Create the webpack configuration file webpack.config.js in the examples directory:

const fs = require('fs')
const path = require('path')
const webpack = require('webpack')

module.exports = {
  mode: 'development',

  /**
   * We will create multiple subdirectories under the examples directory
   * Different chapter demos will be placed in different subdirectories
   * Each subdirectory will have an app.ts file
   * app.ts serves as the webpack build entry file
   * entries collects multiple directory entry files, and each entry also includes a file for hot module replacement
   * entries is an object where the key is the directory name
   */
  entry: fs.readdirSync(__dirname).reduce((entries, dir) => {
    const fullDir = path.join(__dirname, dir)
    const entry = path.join(fullDir, 'app.ts')
    if (fs.statSync(fullDir).isDirectory() && fs.existsSync(entry)) {
      entries[dir] = ['webpack-hot-middleware/client', entry]
    }

    return entries
  }, {}),

  /**
   * Bundle and output target JS based on directory names, matching the directory name
   */
  output: {
    path: path.join(__dirname, '__build__'),
    filename: '[name].js',
    publicPath: '/__build__/'
  },

  module: {
    rules: [
      {
        test: /\.ts$/,
        enforce: 'pre',
        use: [
          {
            loader: 'tslint-loader'
          }
        ]
      },
      {
        test: /\.tsx?$/,
        use: [
          {
            loader: 'ts-loader',
            options: {
              transpileOnly: true
            }
          }
        ]
      }
    ]
  },

  resolve: {
    extensions: ['.ts', '.tsx', '.js']
  },

  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin()
  ]
}
1
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
63
64
65
66
67
68

# Writing the Server File

Create server.js in the examples directory:

const express = require('express')
const bodyParser = require('body-parser')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpackHotMiddleware = require('webpack-hot-middleware')
const WebpackConfig = require('./webpack.config')

const app = express()
const compiler = webpack(WebpackConfig)

app.use(webpackDevMiddleware(compiler, {
  publicPath: '/__build__/',
  stats: {
    colors: true,
    chunks: false
  }
}))

app.use(webpackHotMiddleware(compiler))

app.use(express.static(__dirname))

app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))

const port = process.env.PORT || 8080
module.exports = app.listen(port, () => {
  console.log(`Server listening on http://localhost:${port}, Ctrl+C to stop`)
})
1
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

# Writing the Demo Code

First, create index.html and global.css in the examples directory as the entry file and global stylesheet for all demos.

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>ts-axios examples</title>
    <link rel="stylesheet" href="/global.css">
  </head>
  <body style="padding: 0 20px">
    <h1>ts-axios examples</h1>
    <ul>
      <li><a href="simple">Simple</a></li>
    </ul>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

global.css:

html, body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  color: #2c3e50;
}

ul {
  line-height: 1.5em;
  padding-left: 1.5em;
}

a {
  color: #7f8c8d;
  text-decoration: none;
}

a:hover {
  color: #4fc08d;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Then create a simple directory in examples as this chapter's demo directory, and create index.html and app.ts files inside it.

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Simple example</title>
  </head>
  <body>
    <script src="/__build__/simple.js"></script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10

app.ts:

import axios from '../../src/index'

axios({
  method: 'get',
  url: '/simple/get',
  params: {
    a: 1,
    b: 2
  }
})
1
2
3
4
5
6
7
8
9
10

Since we're sending a request via axios, our server needs to implement the corresponding route. Let's modify server.js and add the following code:

const router = express.Router()

router.get('/simple/get', function(req, res) {
  res.json({
    msg: `hello world`
  })
})

app.use(router)
1
2
3
4
5
6
7
8
9

# Running the Demo

Next, add a new npm script in package.json:

"dev": "node examples/server.js"
1

Then run the following command in the console:

npm run dev
1

This executes node examples/server.js, which starts our server.

Then open Chrome browser and visit http://localhost:8080/ to access our demo. Click into the Simple directory, and through the network tab in Developer Tools, you can see a request was successfully sent and the server's response data is visible.

With that, we've implemented simple request sending and written a demo for it. But there are some problems: the params data we passed in isn't being used or appended to the URL; we haven't handled the request body data format or request headers; and although we received response data at the network level, our code doesn't handle the response data either. In the next chapter, we'll address these issues.

Edit (opens new window)
#TypeScript
Last Updated: 2026/03/21, 12:14:36
Initializing the Project
Handling Request URL Parameters

← Initializing the Project Handling Request URL Parameters→

Recent Updates
01
How I Discovered Disposable Email — A True Story
06-12
02
Animations in Grid Layout
09-15
03
Renaming a Git Branch
08-11
More Articles >
Theme by VDone | Copyright © 2026-2026 Nikolay Tuzov | MIT License | Telegram
  • Auto
  • Light Mode
  • Dark Mode
  • Reading Mode