如何使用TypeScript和Node.js创建一个简单的REST API
Typescript是JavaScript的超集,具有静态类型检查等附加功能。在JavaScript开发者中,Typescript正获得大量的欢迎。它是一种快速发展的编程语言,用于构建广泛的应用程序。
根据Stack Overflow 2020的调查,Typescript以61.7%的得票率成为第二大最受喜爱的语言。
仅高于Django和Kotlin、JavaScript、SQL等流行语言。Slack等流行的应用程序都在Typescript上运行。

就像JavaScript一样,它支持众多框架,如Node.js。
目标
同时使用Typescript和Node.js的主要优势是,开发者可以充分享受这两者的优势。
众所周知,Typescript支持静态打字,在打字过程中检测代码错误。它可以帮助你在开发的早期阶段捕捉错误,创造一个更快的应用开发管道,而不像Node.js(JavaScript)那样,你只能在应用运行时检测错误。在构建广泛的应用程序时,Typescript是一个不错的选择。
另一方面,Node.js因其多样化的开源库、多线程能力、异步和事件驱动的代码执行、快速和轻便等而闻名。
本文将解释如何在Node.js中使用Typescript。我们将使用Typescript和Node.js库创建一个简单的REST API来演示。
该API实现了一些常见的基于Web的API方法,如GET、POST、DELETE、PUT和PATCH。我们将使用一个后期应用。该应用程序将消费一个托管在这个JSON占位符服务器上的Free mock-up API。
先决条件
- 确保你的机器上安装有Node.js和Postman。
- 确保你对如何编写和执行Typescript有基本经验。
- 熟悉Node.js和如何使用Express.js等库。
- 熟悉如何使用Postman(一种与基于Web的API交互的工具)来测试API。
安装Typescript
与JavaScript不同,Typescript并不直接在浏览器上运行。要执行任何Typescript编写的代码,你需要一个Typescript编译器。
这将把Typescript编译成JavaScript。这样一来,在浏览器上执行和运行Typescript会更容易。由于我们使用的是Node.js,我们将使用下面的命令从NPM安装Typescript。
npm install -g typescript
添加–g 标志以在全局范围内安装软件包,确保Typescript对任何Node.js项目都可用。
第1步:初始化Node.js
要启动一个Node.js项目,创建一个项目文件夹并运行npm init 。按照提示操作。这将创建一个package.json 文件,为你的项目保存任何已安装的依赖项。
或者,运行npm init -y 来自动生成package.json 文件。
第2步:安装项目的依赖性
在这个应用程序中,我们将使用以下Node.js库。
- TypeScript:具有静态集合类型定义的TypeScript编译器。
- Ts-node:允许我们运行和配置Typescript执行环境。
- Express:Node.js网络应用框架,用于设置和管理基于网络的服务器。
- @types/express:Express的类型定义。
- Morgan:一个用于Node.js的HTTP请求记录器中间件。
- @types/morgan: Morgan的类型定义。
- Axios:一个基于Node.js承诺的Node.js HTTP客户端库,用于发送HTTP请求以查询和消费API中的资源。
- @types/Axios:Axios的类型定义。
- Nodemon:一个服务器实用程序库,用于监控文本编辑器上的代码变化。每当检测到代码变化时,它就会自动重新启动服务器。
要安装所有这些库,请运行以下命令。
npm install typescript ts-node express @types/express morgan @types/morgan axios @types/axios nodemon
第3步:初始化Typescript
要用Node.js执行Typescript,你需要tsconfig.json 文件。该文件设置了运行Typescript所需的所有环境。你可以手动创建该文件,或者运行tsc --init ,在项目的根部生成一个样本tsconfig.json 。
第4步:设置tsconfig.json
这是一个Typescript编译器的配置文件,其中有指定参数的选项,可以简化Typescript编译和执行管道。
请确保你的文件看起来像这样。
{
"compilerOptions": {
"forceConsistentCasingInFileNames": true,
"module": "commonjs",
"esModuleInterop": true,
"outDir": "./build",
"rootDir": "./source",
"target": "es6",
"skipLibCheck": true,
"strict": true
}
}
第5步:修改package.json
前往你的项目package.json 文件,用下面的值修改main 和scripts 。
"main": "source/server.ts",
"scripts": {
"dev": "nodemon source/server.ts",
"build": "rm -rf build/ && prettier --write source/ && tsc"
}
这将设置命令来构建和编译.ts 文件到.js 文件。在这种情况下,我们就可以使用命令npm run dev 来启动开发服务器。
第6步:设置应用程序的结构
你的项目文件和子文件夹应该设置成如下所示。
| package-lock.json
| package.json
| tsconfig.json
\---source
| server.ts
\---controllers
| posts.ts
\---routes
posts.ts
在你的项目目录内创建source 文件夹。源文件夹将包括应用程序运行所需的所有.ts 文件,如前所述。
设置控制器
创建controllers 文件夹。在它里面有posts.ts 文件。这个模块将处理所有的API逻辑,即获取帖子,获取单个帖子,更新一个帖子,删除一个帖子,以及创建一个帖子。
controllers/posts.ts
/** source/controllers/posts.ts */
import { Request, Response, NextFunction } from 'express';
import axios, { AxiosResponse } from 'axios';
interface Post {
userId: Number;
id: Number;
title: String;
body: String;
}
// getting all posts
const getPosts = async (req: Request, res: Response, next: NextFunction) => {
// get some posts
let result: AxiosResponse = await axios.get(`https://jsonplaceholder.typicode.com/posts`);
let posts: [Post] = result.data;
return res.status(200).json({
message: posts
});
};
// getting a single post
const getPost = async (req: Request, res: Response, next: NextFunction) => {
// get the post id from the req
let id: string = req.params.id;
// get the post
let result: AxiosResponse = await axios.get(`https://jsonplaceholder.typicode.com/posts/${id}`);
let post: Post = result.data;
return res.status(200).json({
message: post
});
};
// updating a post
const updatePost = async (req: Request, res: Response, next: NextFunction) => {
// get the post id from the req.params
let id: string = req.params.id;
// get the data from req.body
let title: string = req.body.title ?? null;
let body: string = req.body.body ?? null;
// update the post
let response: AxiosResponse = await axios.put(`https://jsonplaceholder.typicode.com/posts/${id}`, {
...(title && { title }),
...(body && { body })
});
// return response
return res.status(200).json({
message: response.data
});
};
// deleting a post
const deletePost = async (req: Request, res: Response, next: NextFunction) => {
// get the post id from req.params
let id: string = req.params.id;
// delete the post
let response: AxiosResponse = await axios.delete(`https://jsonplaceholder.typicode.com/posts/${id}`);
// return response
return res.status(200).json({
message: 'post deleted successfully'
});
};
// adding a post
const addPost = async (req: Request, res: Response, next: NextFunction) => {
// get the data from req.body
let title: string = req.body.title;
let body: string = req.body.body;
// add the post
let response: AxiosResponse = await axios.post(`https://jsonplaceholder.typicode.com/posts`, {
title,
body
});
// return response
return res.status(200).json({
message: response.data
});
};
export default { getPosts, getPost, updatePost, deletePost, addPost };
我们包括所有必要的API方法,如。
getPosts- 请求获取列表中的所有帖子。getPost- 通过ID获取单个帖子的请求。updatePost- 用新值更新一个帖子的请求。deletePost- 请求删除一个现有的帖子。addPost- 请求在现有列表中添加一个新的帖子。
添加路由
创建routes 文件夹,其中有posts.ts 文件。该文件将路由连接到它们的控制器。
routes/posts.ts
/** source/routes/posts.ts */
import express from 'express';
import controller from '../controllers/posts';
const router = express.Router();
router.get('/posts', controller.getPosts);
router.get('/posts/:id', controller.getPost);
router.put('/posts/:id', controller.updatePost);
router.delete('/posts/:id', controller.deletePost);
router.post('/posts', controller.addPost);
export = router;
定义所有必要的路由来处理各自的API端点,如GET、POST、PATCH和DELETE(如API控制器模块中定义的)。
设置服务器
server.ts 文件负责设置服务器。这涉及到表达中间件、路由,以及启动服务器。
server.ts
/** source/server.ts */
import http from 'http';
import express, { Express } from 'express';
import morgan from 'morgan';
import routes from './routes/posts';
const router: Express = express();
/** Logging */
router.use(morgan('dev'));
/** Parse the request */
router.use(express.urlencoded({ extended: false }));
/** Takes care of JSON data */
router.use(express.json());
/** RULES OF OUR API */
router.use((req, res, next) => {
// set the CORS policy
res.header('Access-Control-Allow-Origin', '*');
// set the CORS headers
res.header('Access-Control-Allow-Headers', 'origin, X-Requested-With,Content-Type,Accept, Authorization');
// set the CORS method headers
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'GET PATCH DELETE POST');
return res.status(200).json({});
}
next();
});
/** Routes */
router.use('/', routes);
/** Error handling */
router.use((req, res, next) => {
const error = new Error('not found');
return res.status(404).json({
message: error.message
});
});
/** Server */
const httpServer = http.createServer(router);
const PORT: any = process.env.PORT ?? 6060;
httpServer.listen(PORT, () => console.log(`The server is running on port ${PORT}`));
第6步:启动开发服务器
通过运行来启动开发服务器。
npm run dev
这将启动服务器,如下图所示。

第7步:用Postman测试API
Postman是一个基于网络的交互式API测试平台。我们将测试我们先前在路由模块中定义的所有API端点。
1.取出所有帖子
转到Postman,打开一个标签,选择GET ,输入请求的URL为http://localhost:6060/posts 。点击发送来发送这个请求。

这将获取所有的帖子,并向响应部分发送一个响应。响应包括https://jsonplaceholder.typicode.com/posts 中所列的所有帖子。

2.获取单个帖子
就像获取所有的帖子一样,你可以选择只获取一个帖子。这一次,请求的URL将是http://localhost:5000/posts/id 。其中id 是你想获取的帖子的ID。
比方说,获取id为1的帖子,请求的URL将是http://localhost:6060/posts/1 。这应该会返回一个单一的帖子的响应。

3.更新一个帖子
假设你想改变一个帖子的某些值,如标题或帖子的正文。在这种情况下,你要发送一个更新请求。
在Postman方法下拉菜单中,选择PUT 。输入请求的URL为http://localhost:6060/posts/id ,其中id 是你要更新的帖子的ID。
前往正文标签,选择行,在下面的正文标签中,点击右侧下拉菜单中的raw 和JSON 。

在提供的空间中,输入以下内容(请随意改变title 和body 的值),然后点击send 。
{
"title": "Another post title",
"body": "Another post body"
}
这应该会在 "回应 "部分返回一个回应,如下图所示。

4.删除一个帖子
要删除一个帖子,在Postman方法下拉菜单中选择DELETE 。输入请求的URL为http://localhost:6060/posts/id 。
其中id 是你想删除的帖子的任何ID。然后点击发送。

这将返回以下响应。

5.添加一个新的帖子
在Postman方法下拉菜单中选择POST 。在URL部分,输入http://localhost:6060/posts ,在下面的标签中,选择body,点击raw ,在右端下拉菜单中选择JSON ,然后输入。
{
"title": "New post",
"body": "New post body"
}

请随意改变title 和body 的值。点击发送,下面的回复应该返回到回复部分。

总结
Typescript是一种令人难以置信的编程语言。它为开发者提供了在输入代码时检查代码的优势。这样一来,他们甚至可以在运行时间之前就发现错误。
Typescript也是静态类型的。这将增加你在输入和阅读代码时的总体生产时间。