next-openapi-gen 0.0.12 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -3
- package/dist/commands/init.js +44 -30
- package/dist/components/rapidoc.js +20 -0
- package/dist/components/redoc.js +16 -0
- package/dist/components/stoplight.js +17 -0
- package/dist/components/swagger.js +21 -0
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,17 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
**next-openapi-gen** super fast and easy way to generate OpenAPI 3.0 documentation automatically from API routes in a Next.js 14.
|
|
4
4
|
|
|
5
|
+
With support for multiple user interfaces next-openapi-gen makes documenting your API a breeze!
|
|
6
|
+
|
|
5
7
|
## Prerequisites
|
|
6
8
|
|
|
7
9
|
- Nextjs >= 14
|
|
8
10
|
- Node >= 18
|
|
9
11
|
|
|
12
|
+
## Supported interfaces
|
|
13
|
+
|
|
14
|
+
- Swagger
|
|
15
|
+
- Redoc
|
|
16
|
+
- Stoplight Elements
|
|
17
|
+
- RapiDoc
|
|
18
|
+
|
|
10
19
|
## Features
|
|
11
20
|
|
|
12
21
|
- **Automatic OpenAPI Generation**: Generate OpenAPI 3.0 documentation from your Next.js routes, automatically parsing TypeScript types for parameters, request bodies and responses.
|
|
13
22
|
- **TypeScript Type Scanning**: Automatically resolve TypeScript types for params, body, and responses based on your API endpoint's TypeScript definitions. Field comments in TypeScript types are reflected as descriptions in the OpenAPI schema.
|
|
14
|
-
- **JSDoc-Based Documentation**: Document API routes with JSDoc comments, including tags like `@openapi`, `@auth`, `@desc`, `@params`, `@body`, and `@response` to easily define route metadata.
|
|
15
|
-
- **UI Interface Options**: Choose between Swagger UI
|
|
23
|
+
- **JSDoc-Based Documentation (Optional)**: Document API routes with JSDoc comments, including tags like `@openapi`, `@auth`, `@desc`, `@params`, `@body`, and `@response` to easily define route metadata.
|
|
24
|
+
- **UI Interface Options**: Choose between `Swagger UI`, `Redoc`, `Stoplight Elements` or `RapiDoc` to visualize your API documentation. Customize the interface to fit your preferences.
|
|
16
25
|
- **Real-time Documentation**: As your API evolves, regenerate the OpenAPI documentation with a single command, ensuring your documentation is always up to date.
|
|
17
26
|
- **Easy configuration**: Customize generator behavior using the `next.openapi.json` configuration file, allowing for quick adjustments without modifying the code.
|
|
18
27
|
|
|
@@ -29,9 +38,13 @@ yarn add next-openapi-gen
|
|
|
29
38
|
Run the following command to generate the `next.openapi.json` configuration file and automatically set up Swagger UI with `/api-docs` routes:
|
|
30
39
|
|
|
31
40
|
```bash
|
|
32
|
-
npx next-openapi-gen init
|
|
41
|
+
npx next-openapi-gen init --ui swagger --docs-url api-docs
|
|
33
42
|
```
|
|
34
43
|
|
|
44
|
+
Parameters:
|
|
45
|
+
- **ui**: `swagger` | `redoc` | `stoplight` | `rapidoc`
|
|
46
|
+
- **docs-url**: url on which api docs will be visible
|
|
47
|
+
|
|
35
48
|
This command does the following:
|
|
36
49
|
|
|
37
50
|
- Generates a `next.openapi.json` file, which stores the OpenAPI configuration for your project.
|
package/dist/commands/init.js
CHANGED
|
@@ -5,6 +5,10 @@ import ora from "ora";
|
|
|
5
5
|
import { exec } from "child_process";
|
|
6
6
|
import util from "util";
|
|
7
7
|
import openapiTemplate from "../openapi-template.js";
|
|
8
|
+
import { swaggerDeps, SwaggerUI } from "../components/swagger.js";
|
|
9
|
+
import { redocDeps, RedocUI } from "../components/redoc.js";
|
|
10
|
+
import { stoplightDeps, StoplightUI } from "../components/stoplight.js";
|
|
11
|
+
import { rapidocDeps, RapidocUI } from "../components/rapidoc.js";
|
|
8
12
|
const execPromise = util.promisify(exec);
|
|
9
13
|
const spinner = ora("Initializing project with OpenAPI template...\n");
|
|
10
14
|
const getPackageManager = async () => {
|
|
@@ -28,43 +32,55 @@ const getPackageManager = async () => {
|
|
|
28
32
|
// Default to npm if no lock files are found
|
|
29
33
|
return "npm";
|
|
30
34
|
};
|
|
31
|
-
|
|
35
|
+
function getDocsPage(ui, outputFile) {
|
|
36
|
+
let DocsComponent = SwaggerUI;
|
|
37
|
+
if (ui === "redoc") {
|
|
38
|
+
DocsComponent = RedocUI;
|
|
39
|
+
}
|
|
40
|
+
else if (ui === "stoplight") {
|
|
41
|
+
DocsComponent = StoplightUI;
|
|
42
|
+
}
|
|
43
|
+
else if (ui === "rapidoc") {
|
|
44
|
+
DocsComponent = RapidocUI;
|
|
45
|
+
}
|
|
46
|
+
return DocsComponent(outputFile);
|
|
47
|
+
}
|
|
48
|
+
function getDocsPageDependencies(ui) {
|
|
49
|
+
let deps = [];
|
|
50
|
+
if (ui === "swagger") {
|
|
51
|
+
deps = swaggerDeps;
|
|
52
|
+
}
|
|
53
|
+
else if (ui === "redoc") {
|
|
54
|
+
deps = redocDeps;
|
|
55
|
+
}
|
|
56
|
+
else if (ui === "stoplight") {
|
|
57
|
+
deps = stoplightDeps;
|
|
58
|
+
}
|
|
59
|
+
else if (ui === "rapidoc") {
|
|
60
|
+
deps = rapidocDeps;
|
|
61
|
+
}
|
|
62
|
+
return deps.join(" ");
|
|
63
|
+
}
|
|
64
|
+
async function createDocsPage(ui, outputFile) {
|
|
32
65
|
const paths = ["app", "api-docs"];
|
|
33
66
|
const srcPath = path.join(process.cwd(), "src");
|
|
34
|
-
const { outputFile } = openapiTemplate;
|
|
35
67
|
if (fs.existsSync(srcPath)) {
|
|
36
68
|
paths.unshift("src");
|
|
37
69
|
}
|
|
38
70
|
const docsDir = path.join(process.cwd(), ...paths);
|
|
39
71
|
await fs.promises.mkdir(docsDir, { recursive: true });
|
|
40
|
-
const
|
|
41
|
-
import "swagger-ui-react/swagger-ui.css";
|
|
42
|
-
|
|
43
|
-
import dynamic from "next/dynamic";
|
|
44
|
-
|
|
45
|
-
const SwaggerUI = dynamic(() => import("swagger-ui-react"), {
|
|
46
|
-
ssr: false,
|
|
47
|
-
loading: () => <p>Loading Component...</p>,
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
export default async function ApiDocsPage() {
|
|
51
|
-
return (
|
|
52
|
-
<section>
|
|
53
|
-
<SwaggerUI url="/${outputFile}" />
|
|
54
|
-
</section>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
`;
|
|
72
|
+
const docsPage = getDocsPage(ui, outputFile);
|
|
58
73
|
const componentPath = path.join(docsDir, "page.tsx");
|
|
59
|
-
await fs.promises.writeFile(componentPath,
|
|
60
|
-
spinner.succeed(`Created ${paths.join("/")}/page.tsx for
|
|
74
|
+
await fs.promises.writeFile(componentPath, docsPage.trim());
|
|
75
|
+
spinner.succeed(`Created ${paths.join("/")}/page.tsx for ${ui}.`);
|
|
61
76
|
}
|
|
62
|
-
async function
|
|
77
|
+
async function installDependencies(ui) {
|
|
63
78
|
const packageManager = await getPackageManager();
|
|
64
79
|
const installCmd = `${packageManager} ${packageManager === "npm" ? "install" : "add"}`;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
80
|
+
const deps = getDocsPageDependencies(ui);
|
|
81
|
+
spinner.succeed(`Installing ${deps} dependencies...`);
|
|
82
|
+
const resp = await execPromise(`${installCmd} ${deps}`);
|
|
83
|
+
spinner.succeed(`Successfully installed ${deps}.`);
|
|
68
84
|
}
|
|
69
85
|
function extendOpenApiTemplate(spec, options) {
|
|
70
86
|
spec.ui = options.ui ?? spec.ui;
|
|
@@ -79,10 +95,8 @@ export async function init(options) {
|
|
|
79
95
|
extendOpenApiTemplate(template, { docsUrl, ui });
|
|
80
96
|
await fse.writeJson(outputPath, template, { spaces: 2 });
|
|
81
97
|
spinner.succeed(`Created OpenAPI template in next.openapi.json`);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
installSwagger();
|
|
85
|
-
}
|
|
98
|
+
createDocsPage(ui, template.outputFile);
|
|
99
|
+
installDependencies(ui);
|
|
86
100
|
}
|
|
87
101
|
catch (error) {
|
|
88
102
|
spinner.fail(`Failed to initialize project: ${error.message}`);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const rapidocDeps = ["rapidoc"];
|
|
2
|
+
export function RapidocUI(outputFile) {
|
|
3
|
+
return `
|
|
4
|
+
"use client";
|
|
5
|
+
|
|
6
|
+
import "rapidoc";
|
|
7
|
+
|
|
8
|
+
export default function ApiDocsPage() {
|
|
9
|
+
return (
|
|
10
|
+
<section style={{ height: "100vh" }}>
|
|
11
|
+
<rapi-doc
|
|
12
|
+
spec-url="${outputFile}"
|
|
13
|
+
render-style="read"
|
|
14
|
+
style={{ height: "100vh", width: "100%" }}
|
|
15
|
+
></rapi-doc>
|
|
16
|
+
</section>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const redocDeps = ["redoc"];
|
|
2
|
+
export function RedocUI(outputFile) {
|
|
3
|
+
return `
|
|
4
|
+
"use client";
|
|
5
|
+
|
|
6
|
+
import { RedocStandalone } from "redoc";
|
|
7
|
+
|
|
8
|
+
export default async function ApiDocsPage() {
|
|
9
|
+
return (
|
|
10
|
+
<section>
|
|
11
|
+
<RedocStandalone specUrl="/${outputFile}" />
|
|
12
|
+
</section>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const stoplightDeps = ["@stoplight/element"];
|
|
2
|
+
export function StoplightUI(outputFile) {
|
|
3
|
+
return `
|
|
4
|
+
"use client";
|
|
5
|
+
|
|
6
|
+
import { API } from "@stoplight/elements";
|
|
7
|
+
import "@stoplight/elements/styles.min.css";
|
|
8
|
+
|
|
9
|
+
export default function ApiDocsPage() {
|
|
10
|
+
return (
|
|
11
|
+
<section style={{ height: "100vh" }}>
|
|
12
|
+
<API apiDescriptionUrl="${outputFile}" />
|
|
13
|
+
</section>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const swaggerDeps = ["swagger-ui"];
|
|
2
|
+
export function SwaggerUI(outputFile) {
|
|
3
|
+
return `
|
|
4
|
+
import "swagger-ui-react/swagger-ui.css";
|
|
5
|
+
|
|
6
|
+
import dynamic from "next/dynamic";
|
|
7
|
+
|
|
8
|
+
const SwaggerUI = dynamic(() => import("swagger-ui-react"), {
|
|
9
|
+
ssr: false,
|
|
10
|
+
loading: () => <p>Loading Component...</p>,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export default async function ApiDocsPage() {
|
|
14
|
+
return (
|
|
15
|
+
<section>
|
|
16
|
+
<SwaggerUI url="/${outputFile}" />
|
|
17
|
+
</section>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ program
|
|
|
10
10
|
program
|
|
11
11
|
.command("init")
|
|
12
12
|
.addOption(new Option("-i, --ui <type>", "Specify the UI type, e.g., swagger")
|
|
13
|
-
.choices(["swagger", "
|
|
13
|
+
.choices(["swagger", "redoc", "stoplight", "rapidoc"])
|
|
14
14
|
.default("swagger"))
|
|
15
15
|
.option("-u, --docs-url <url>", "Specify the docs URL", "api-docs")
|
|
16
16
|
.description("Initialize a openapi specification")
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-openapi-gen",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Super fast and easy way to generate OpenAPI documentation automatically from API routes in a NextJS 14
|
|
3
|
+
"version": "0.0.14",
|
|
4
|
+
"description": "Super fast and easy way to generate OpenAPI documentation automatically from API routes in a NextJS 14",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.mjs",
|