试用 NestJS 第 4 部分:从 OpenAPI 文档生成 Typescript 客户端
本文最初发表于我的个人博客. 简介 在我的上一篇博文中,我们看到使用 NestJS 开始使用 OpenAPI 是多么容易。 在这篇博文中,我想向您展示如何利用生成的 OpenAPI 文档来生成将在 React 应用程序中使用的 typescript 客户端。 我为什么要这么做?我喜欢有静态类型的端点,而不是自己打字。此外,它是自动生成的,这意味着我们可以在 CI 中自动生成,并确保在编译时一切正常
本文最初发表于我的个人博客.
简介
在我的上一篇博文中,我们看到使用 NestJS 开始使用 OpenAPI 是多么容易。
在这篇博文中,我想向您展示如何利用生成的 OpenAPI 文档来生成将在 React 应用程序中使用的 typescript 客户端。
我为什么要这么做?我喜欢有静态类型的端点,而不是自己打字。此外,它是自动生成的,这意味着我们可以在 CI 中自动生成,并确保在编译时一切正常。
入门
该项目这一部分的源代码可在此处获得:https://github.com/arnaud-cortisse/trying-out-nestjs-part-4。
OpenAPI 生成器
我们可以使用很多工具来生成 OpenAPI 客户端。
我要使用的是以下内容:typescript-axios。
OpenAPI 文档
在上一篇博文中,我只告诉过你http://localhost:3001/api/
,它承载了 Swagger UI。
但是还有另一个关键端点:http://localhost:3001/api-json
。该端点托管生成的 OpenAPI 文档,我们将参考该文档以生成客户端。
为 OpenAPI 生成器设置环境
OpenAPI 生成器工具要求我们在我们的机器上安装几个依赖项,但我不喜欢让我的机器因项目特定的依赖项而膨胀。
让我们再次尝试使用 Docker!
准备文件
在根文件夹中,执行以下命令:
-
mkdir -p tools/openapi-generator
-
cd tools/openapi-generator
-
touch Dockerfile
-
touch openapitools.json
-
touch generate.sh
-
touch .gitignore
工具/openapi-generator/Dockerfile
通过访问 NestJS 的/api-json
端点,此 docker 映像将用于生成 OpenAPI 文档。
FROM timbru31/java-node:jdk-14
RUN npm install @openapitools/openapi-generator-cli -g
RUN mkdir /local
WORKDIR /local
COPY . .
CMD ["sh", "generate.sh"]
进入全屏模式 退出全屏模式
-
我们使用预装了 JDK 的 docker 镜像(因为
openapi-generator-cli
需要它)。 -
我们安装
openapi-generator-cli
。 -
我们创建一个文件夹
/local
并将/tools/openapi-generator
中的所有内容复制到其中。 -
启动图像时,我们启动脚本generate.sh(我们仍然需要填充它)。
工具/openapi-generator/openapitools.json
OpenAPI 生成器配置文件。有关详细信息,请参阅配置。
{
"$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json",
"spaces": 2,
"generator-cli": {
"version": "5.0.0"
}
}
进入全屏模式 退出全屏模式
工具/openapi-generator/generate.sh
启动新定义的Dockerfile
时执行的脚本。
openapi-generator-cli generate \
-i http://nestjs:3001/api-json \
--generator-name typescript-axios \
-o /local/out \
--additional-properties=useSingleRequestParameter=true
进入全屏模式 退出全屏模式
-
-i
参数表示 OpenAPI 文档所在的位置。在这里,我决定使用http://nestjs:3001/api-json而不是http://localhost:3001/api-json(两者都可以,但我更喜欢前者)。您将无法在浏览器中访问http://nestjs:3001/api-json,因为它不是您能够在您的机器上解析的名称(但这可以在 docker-compose 中解析,因为两个图像都将在同一个网络中运行)。 -
--generator-name
表示我们要使用的生成器。 -
-o
表示我们要在哪里输出生成的文件。 -
--additional-properties
用于为生成器提供附加参数(参见本页)。
工具/openapi-generator/.gitignore
我们不想在此文件夹中对生成器输出的文件进行版本控制(但我们将在 React 应用程序中对生成的文件进行版本控制)。
.build
进入全屏模式 退出全屏模式
修改docker-compose.yml
让我们可以从现有的docker-compose
文件开始openapi_generator
。
openapi_generator:
build:
context: ./tools/openapi-generator
dockerfile: Dockerfile
depends_on:
- nestjs
volumes:
- ./tools/openapi-generator/.build:/local/out
进入全屏模式 退出全屏模式
-
我们使服务依赖于
nestjs
。这样,如果之前没有启动过nestjs
,它将启动它。实际上,nestjs
必须运行才能使openapi_generator
能够生成客户端 API。 -
我们将文件夹
./tools/openapi-generator/.build
挂载到服务中,将在其中生成客户端(我们在上面自己配置了该路径)。这样,我们就可以访问主机上生成的文件。
修改根package.json
在根package.json
中,添加以下脚本:
"scripts": {
...
"generate-api-client": "docker-compose up --build openapi_generator"
...
}
进入全屏模式 退出全屏模式
试用 OpenAPI 生成器
在根文件夹中,键入以下内容:
npm run generate-api-client
。
如果一切顺利,您应该在此文件夹中有文件:tools/openapi-generator/.build
。
如果您没有任何文件,可能是因为nestjs
服务在生成器尝试访问它时尚未准备好。只需尝试重新启动npm run generate-api-client
,一切都应该没问题。
将客户端交付给 React App。
在根文件夹中,执行以下命令:
-
mkdir scripts
-
touch scripts/update-api.sh
更新-api.sh
#!/bin/bash
cd "$(dirname "$0")"
SOURCE_FOLDER="../tools/openapi-generator/.build"
DEST_FOLDER="../packages/react-app/src/api/generated"
rm -rf $DEST_FOLDER
mkdir -p $DEST_FOLDER
cp $SOURCE_FOLDER/**.ts $DEST_FOLDER
进入全屏模式 退出全屏模式
使用这个脚本,我们实质上是将服务openapi_generator
自动生成的文件交付给 React 应用程序。
修改根package.json
在根package.json
中,添加以下脚本:
"scripts": {
...
"update-api-client": "sh ./scripts/update-api.sh",
"generate-and-update-api-client": "npm run generate-api-client && npm run update-api-client"
...
}
进入全屏模式 退出全屏模式
试用传递机制
在根文件夹中,键入以下内容:
npm run generate-and-update-api-client
。
如果一切顺利,您应该在packages/react-app/src/api/generated
中有文件。
在 React App 中使用客户端
安装新的依赖项
在packages/react-app/src
目录下,执行以下命令:
npm install axios react-query
删除部分文件
-
cd packages/react-app/src
-
rm App.css App.test.tsx App.tsx
创建新文件
-
cd packages/react-app/src
-
mkdir axios
-
mkdir api
(但它应该已经存在) -
mkdir components
-
touch axios/axios-client.ts
-
touch api/api.ts
-
touch components/App.tsx
-
touch components/Example.tsx
包/react-app/src/axios/axios-client.ts
用于配置 axios 实例,使其预先配置为访问 NestJS。
import axios, { AxiosRequestConfig } from "axios";
export const axiosBaseUrl = `${process.env.REACT_APP_BACKEND_SCHEMA}://${process.env.REACT_APP_BACKEND_HOSTNAME}:${process.env.REACT_APP_BACKEND_PORT}`;
export const axiosConfig: AxiosRequestConfig = {
baseURL: axiosBaseUrl,
};
const axiosBackendClient = axios.create(axiosConfig);
export default axiosBackendClient;
进入全屏模式 退出全屏模式
包/react-app/src/api/api.ts
配置TasksApi
的实例(由生成器自动生成的类),我们将使用它与后端进行通信。
import axiosBackendClient, { axiosBaseUrl } from "../axios/axios-client";
import { TasksApi } from "./generated";
export const tasksApi = new TasksApi(
{
basePath: axiosBaseUrl,
isJsonMime: () => false,
},
undefined,
axiosBackendClient
);
进入全屏模式 退出全屏模式
包/react-app/src/components/App.tsx
import React from "react";
import { QueryClient, QueryClientProvider } from "react-query";
import Example from "./Example";
const queryClient = new QueryClient();
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
);
}
进入全屏模式 退出全屏模式
-
我们配置
react-query
提供者。 -
我们渲染
Example
组件(尚未定义)。
包/react-app/src/components/Example.tsx
import { useQuery } from "react-query";
import { tasksApi } from "../api/api";
export default function Example() {
const id = "fake id";
const { isLoading, error, data } = useQuery(`tasks_find_one_${id}`, () =>
tasksApi.tasksControllerFindOne({
id,
})
);
if (isLoading) return <div>Loading...</div>;
if (error as Error) return <div>An error has occurred</div>;
return <div>{data?.data.title}</div>;
}
进入全屏模式 退出全屏模式
看看查询。这就是神奇的地方:我们利用自动生成的客户端,因此拥有静态类型的所有好处。
修改现有文件
包/react-app/src/index.tsx
我刚刚删除了一些无用的行(在本博客的上下文中)并从适当的路径导入了App
组件。
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./components/App";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
进入全屏模式 退出全屏模式
试用客户端
在根文件夹中,执行以下操作:
docker-compose up --build
(可能需要一段时间,因为要安装的 React App 中有新的依赖项)。
在浏览器中浏览http://localhost:3000/
。
您应该在某个时候收到以下消息:An error has occurred
。
打开您的开发人员工具:您应该会看到 CORS 错误。我们可以通过更新 Nest 应用来解决这个问题。
启用 CORS
在packages/nestjs/src/main.ts
中,添加以下内容
...
app.enableCors();
...
进入全屏模式 退出全屏模式
请注意,您绝对应该在生产环境中适当地配置 CORS 规则。
测试一切
现在,如果您在浏览器中继续http://localhost:3000/
,您应该会看到消息fake title
。
这意味着我们确实能够使用自动生成的客户端与我们的 API 进行通信。
最后的话
设置一切并不简单。尽管如此,我们现在有了一种与 API 通信的好方法:我们有一个类型化的客户端,它将极大地改善 React 内部的开发体验。更重要的是,重新生成该客户端以使其匹配最新的 API 基本上不需要任何成本。最后,我们现在能够在编译时检测到 React 应用和 NestJS 应用之间的任何不同步。
更多推荐
所有评论(0)