岁岁安安 發表於 2025-9-18 15:36:00

在Next.js中集成swagger文档

<h1 class="postTitle"><span>在Next.js中集成swagger文档</span></h1>
<div class="clear">&nbsp;</div>
<div class="postBody">
<div id="cnblogs_post_body" class="blogpost-body cnblogs-markdown">
<h2 id="前言">前言#</h2>
<p>最近一直在用 Next.js 开发我的新网站</p>
<p>这次写了一些 API</p>
<p>我就想着能不能像平时开发后端那样,使用 swagger 进行调试</p>
<p>所以进行了一番调研</p>
<p>严格来说&nbsp;Next.js 本身并不直接支持 swagger,因为 swagger(更准确地说是&nbsp;OpenAPI 规范)是后端 API 文档的工具,而 Next.js 是一个前端/全栈框架。</p>
<p>不过,如果用 Next.js 的&nbsp;API Routes(即&nbsp;<code>app/api/*</code>&nbsp;目录下的接口),完全可以结合 swagger 来做 API 文档。常见做法有两种:</p>
<ul>
<li>使用工具自动生成 swagger</li>
<li>手动写 OpenAPI 文件</li>
</ul>
<h2 id="自动生成">自动生成#</h2>
<p>可以用工具根据 TypeScript 类型自动生成:</p>
<ul>
<li>tsoa</li>
<li>zod-to-openapi(如果用了 Zod 校验)</li>
<li>next-swagger-doc(专门为 Next.js 封装的工具)</li>
</ul>
<p>既然有为 Next.js 设计的工具,那我肯定直接用这第三个了</p>
<h2 id="next-swagger-doc">next-swagger-doc#</h2>
<p>我实际用下来这个工具也不咋样</p>
<p>因为 Next.js 官方没有实现强类型的 API</p>
<p>所以需要自己定义每一个接口的 schema ,麻烦得一批</p>
<p>不过既然已经试用过了,也介绍一下吧</p>
<h3 id="安装">安装#</h3>
<pre class="highlighter-hljs"><code class="language-bash highlighter-hljs hljs">bun i next-swagger-doc
</code></pre>
<h3 id="使用">使用#</h3>
<p>这个工具的 README.md 文档有点老了</p>
<p>好在 examples 不老,里面有提供 Next.js 15 的项目例子</p>
<p>https://github.com/jellydn/next-swagger-doc/tree/main/examples</p>
<p>直接跟着配置吧</p>
<h3 id="创建-swagger-spec">创建 Swagger Spec#</h3>
<p>创建&nbsp;<code>lib/swagger.ts</code>&nbsp;文件</p>
<pre class="highlighter-hljs"><code class="language-ts highlighter-hljs hljs language-typescript"><span class="hljs-keyword">import { createSwaggerSpec } <span class="hljs-keyword">from <span class="hljs-string">'next-swagger-doc';

<span class="hljs-keyword">import <span class="hljs-string">'server-only';

<span class="hljs-keyword">export <span class="hljs-keyword">const <span class="hljs-title function_">getApiDocs = <span class="hljs-keyword">async (<span class="hljs-params">) =&gt; {
<span class="hljs-keyword">const spec = <span class="hljs-title function_">createSwaggerSpec({
    <span class="hljs-attr">apiFolder: <span class="hljs-string">'app/api',
    <span class="hljs-attr">definition: {
      <span class="hljs-attr">openapi: <span class="hljs-string">'3.0.0',
      <span class="hljs-attr">info: {
      <span class="hljs-attr">title: <span class="hljs-string">'Next Swagger API Example',
      <span class="hljs-attr">version: <span class="hljs-string">'1.0',
      },
      <span class="hljs-attr">components: {
      <span class="hljs-attr">securitySchemes: {
          <span class="hljs-title class_">BearerAuth: {
            <span class="hljs-attr">type: <span class="hljs-string">'http',
            <span class="hljs-attr">scheme: <span class="hljs-string">'bearer',
            <span class="hljs-attr">bearerFormat: <span class="hljs-string">'JWT',
          },
          <span class="hljs-title class_">OAuth2: {
            <span class="hljs-attr">type: <span class="hljs-string">'oauth2',
            <span class="hljs-attr">flows: {
            <span class="hljs-attr">authorizationCode: {
                <span class="hljs-attr">authorizationUrl: <span class="hljs-string">'https://example.com/oauth/authorize',
                <span class="hljs-attr">tokenUrl: <span class="hljs-string">'https://example.com/oauth/token',
                <span class="hljs-attr">scopes: {
                  <span class="hljs-attr">read: <span class="hljs-string">'Grants read access',
                  <span class="hljs-attr">write: <span class="hljs-string">'Grants write access',
                },
            },
            },
          },
      },
      },
      <span class="hljs-attr">security: [],
    },
});
<span class="hljs-keyword">return spec;
};
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h3 id="创建-swagger-ui-component">创建 Swagger UI Component#</h3>
<p>这个可以生成 swagger 的界面</p>
<p>有多种工具能实现这个功能</p>
<p>next-swagger-doc 用的是&nbsp;swagger-ui-react</p>
<pre class="highlighter-hljs"><code class="language-bash highlighter-hljs hljs">bun i swagger-ui-react
</code></pre>
<p>我这里先跟着配置一下,等会再试试 Node.js 生态的其他工具,比如&nbsp;stoplightio/elements</p>
<p>创建&nbsp;<code>app/api-doc/react-swagger.tsx</code>&nbsp;文件</p>
<pre class="highlighter-hljs"><code class="language-tsx highlighter-hljs hljs language-typescript"><span class="hljs-string">'use client';

<span class="hljs-keyword">import <span class="hljs-title class_">SwaggerUI <span class="hljs-keyword">from <span class="hljs-string">'swagger-ui-react';

<span class="hljs-keyword">import <span class="hljs-string">'swagger-ui-react/swagger-ui.css';

<span class="hljs-keyword">type <span class="hljs-title class_">Props = {
    <span class="hljs-attr">spec: <span class="hljs-title class_">Record&lt;<span class="hljs-built_in">string, <span class="hljs-built_in">any&gt;;
};

<span class="hljs-keyword">function <span class="hljs-title function_">ReactSwagger(<span class="hljs-params">{ spec }: Props) {
    <span class="hljs-comment">// @ts-ignore - SwaggerUI is not typed
    <span class="hljs-keyword">return <span class="language-xml">&lt;<span class="hljs-name">SwaggerUI <span class="hljs-attr">spec=<span class="hljs-string">{spec} /&gt;;
}

<span class="hljs-keyword">export <span class="hljs-keyword">default <span class="hljs-title class_">ReactSwagger;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h3 id="创建-api-文档页面">创建 API 文档页面#</h3>
<p>就是把上面说的 Swagger UI Component 包装成页面</p>
<p>创建&nbsp;<code>app/api-doc/page.tsx</code>&nbsp;文件</p>
<pre class="highlighter-hljs"><code class="language-tsx highlighter-hljs hljs language-typescript"><span class="hljs-keyword">import { getApiDocs } <span class="hljs-keyword">from <span class="hljs-string">'@/lib/swagger';

<span class="hljs-keyword">import <span class="hljs-title class_">ReactSwagger <span class="hljs-keyword">from <span class="hljs-string">'./react-swagger';

<span class="hljs-keyword">export <span class="hljs-keyword">default <span class="hljs-keyword">async <span class="hljs-keyword">function <span class="hljs-title function_">IndexPage(<span class="hljs-params">) {
<span class="hljs-keyword">const spec = <span class="hljs-keyword">await <span class="hljs-title function_">getApiDocs();
<span class="hljs-keyword">return (
    <span class="language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">section <span class="hljs-attr">className=<span class="hljs-string">"container"&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">ReactSwagger <span class="hljs-attr">spec=<span class="hljs-string">{spec} /&gt;
    <span class="hljs-tag">&lt;/<span class="hljs-name">section&gt;
);
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h3 id="添加接口文档注释">添加接口文档注释#</h3>
<p>很麻烦,这个库不能根据路径自动识别接口,只能手动定义</p>
<p>添加后 swagger 文档的可读性更高</p>
<pre class="highlighter-hljs"><code class="language-ts highlighter-hljs hljs language-typescript"><span class="hljs-comment">/**
* <span class="hljs-doctag">@swagger
* /api/hello:
*   get:
*   description: Returns the hello world
*   responses:
*       200:
*         description: Hello World!
*/
<span class="hljs-keyword">export <span class="hljs-keyword">async <span class="hljs-keyword">function <span class="hljs-title function_">GET(<span class="hljs-params">_request: Request) {
<span class="hljs-comment">// Do whatever you want
<span class="hljs-keyword">return <span class="hljs-keyword">new <span class="hljs-title class_">Response(<span class="hljs-string">'Hello World!', {
    <span class="hljs-attr">status: <span class="hljs-number">200,
});
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h3 id="查看效果">查看效果#</h3>
<p>访问&nbsp;http://localhost:3000/api-doc&nbsp;查看接口文档</p>
<h2 id="手动生成">手动生成#</h2>
<p>使用 swagger-jsdoc 之类的工具从 API route 上生成 OpenAPI spec</p>
<p>把&nbsp;<code>swagger.json</code>&nbsp;放在&nbsp;<code>public</code>&nbsp;目录里</p>
<p>然后搭配前面提到的 swagger-ui-react 之类的工具来实现 swagger 文档展示</p>
<pre class="highlighter-hljs"><code class="language-tsx highlighter-hljs hljs language-typescript"><span class="hljs-keyword">import dynamic <span class="hljs-keyword">from <span class="hljs-string">'next/dynamic';

<span class="hljs-keyword">const <span class="hljs-title class_">SwaggerUI = <span class="hljs-title function_">dynamic(<span class="hljs-function">() =&gt; <span class="hljs-title function_">import(<span class="hljs-string">'swagger-ui-react'), { <span class="hljs-attr">ssr: <span class="hljs-literal">false });
<span class="hljs-keyword">import <span class="hljs-string">'swagger-ui-react/swagger-ui.css';

<span class="hljs-keyword">export <span class="hljs-keyword">default <span class="hljs-keyword">function <span class="hljs-title function_">ApiDocs(<span class="hljs-params">) {
<span class="hljs-keyword">return <span class="language-xml">&lt;<span class="hljs-name">SwaggerUI <span class="hljs-attr">url=<span class="hljs-string">"/swagger.json" /&gt;;
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>可以参考:&nbsp;Swagger integration in next JS</p>
<h2 id="小结">小结#</h2>
<p>这俩方法看起来都不是很完美</p>
<p>果然 Next.js 还是偏前端吧,写太多 API 也不合适</p>
<p>我最近又发现一个新玩意&nbsp;hono&nbsp;,这个框架对 edge 的支持非常好,可以考虑拿这个搭配 Next.js 来做一些小玩意</p>
<p>不得不说前端的技术栈更新太快了哈哈哈</p>
</div>
<div class="esa-post-signature">
<p>作者:DealiAxy</p>
<p>出处:https://www.cnblogs.com/deali/p/19069135/nextjs-integrate-swagger-docs</p>
<p>版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。</p>
<p>微信公众号:「程序设计实验室」<br>新版StarBlog已经上线,地址:http://blog.deali.cn</p>

</div>
<div id="MySignature">微信公众号:「程序设计实验室」 专注于互联网热门新技术探索与团队敏捷开发实践,包括架构设计、机器学习与数据分析算法、移动端开发、Linux、Web前后端开发等,欢迎一起探讨技术,分享学习实践经验。</div>

</div>

</div>
<div id="MySignature" role="contentinfo">
    漫思<br><br>
来源:https://www.cnblogs.com/sexintercourse/p/19098910
頁: [1]
查看完整版本: 在Next.js中集成swagger文档