Generate OpenAPI (Swagger) specifications automatically from your JSDoc comments.
This package parses your existing code comments to create comprehensive API documentation, saving you time and effort.
It is designed for speed and minimal runtime overhead, building upon the foundations of JSDoc and Swagger standards.
Note: This package originated as a fork of openapi-comment-parser and swagger-jsdoc.
Daniel Bannert's open source work is supported by the community on GitHub Sponsors
- Automatic Generation: Creates OpenAPI specs from JSDoc comments.
- Multiple Syntaxes: Supports standard OpenAPI YAML/JSON within comments and a concise short syntax.
- CLI Tool: Provides a command-line interface for easy generation.
- Programmatic API: Offers a JavaScript API for integration into build processes.
- Framework Integration: Includes helpers like a Webpack plugin (useful for Next.js).
- Performance: Focused on speed and low overhead.
npm install @visulima/jsdoc-open-api
yarn add @visulima/jsdoc-open-api
pnpm add @visulima/jsdoc-open-api
You can use @visulima/jsdoc-open-api
in several ways:
- Via Command Line (CLI): Quick generation for simple use cases or manual runs.
- Programmatically: Integrate generation into your custom scripts or build tools.
- With Webpack (e.g., Next.js): Automate generation during your build process.
Choose the syntax you prefer for defining OpenAPI details within your JSDoc comments:
The Command Line Interface (CLI) provides a straightforward way to generate your OpenAPI specification.
Instead of installing the CLI globally or relying on optional dependencies, you can run the installed binary directly using your package manager:
# With npx (comes with npm)
npx jsdoc-open-api generate src/
# Or explicitly using the package name:
npx @visulima/jsdoc-open-api generate src/
# With pnpm
pnpm exec jsdoc-open-api generate src/
# With Yarn 1.x
yarn run jsdoc-open-api generate src/
# With Yarn Berry (2+)
yarn jsdoc-open-api generate src/
This is often the recommended way to use package binaries within a project.
The CLI relies on commander
and cli-progress
. These are listed as optionalDependencies
. Depending on your package manager (npm/yarn/pnpm) and configuration, you might need to install them manually if they weren't installed automatically:
# If needed:
npm install commander cli-progress
# or
yarn add commander cli-progress
# or
pnpm add commander cli-progress
Initializes the project by creating a .openapirc.js
configuration file. This is typically run once per project.
jsdoc-open-api init
Parses your source files based on the configuration (or command-line arguments) and generates the OpenAPI specification file.
# Generate using defaults defined in .openapirc.js (if it exists)
jsdoc-open-api generate
# Specify input path(s) directly
jsdoc-open-api generate src/routes/**/*.js src/controllers/
# Specify output file
jsdoc-open-api generate -o ./public/swagger.json src/
# Use verbose output
jsdoc-open-api generate -v src/
# Use very verbose output for debugging
jsdoc-open-api generate -d src/
jsdoc-open-api generate [options] [path ...]
-
[path ...]
: Paths to files or directories to parse (optional, uses configuration if not provided). -
-c, --config [.openapirc.js]
: Specify the configuration file path. Defaults to.openapirc.js
. -
-o, --output [swaggerSpec.json]
: Specify the output file for the OpenAPI specification. Defaults toswaggerSpec.json
. -
-v, --verbose
: Enable verbose output during generation. -
-d, --very-verbose
: Enable very verbose output for detailed debugging.
You can integrate the generation process directly into your Node.js scripts.
import path from "node:path";
import { fileURLToPath } from "node:url";
import jsdocOpenApi from "@visulima/jsdoc-open-api"; // Adjust import based on your module system (require vs import)
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const options = {
definition: {
openapi: "3.0.0",
info: {
title: "My Programmatic API",
version: "1.0.0",
description: "API documentation generated programmatically",
},
// Add other base OpenAPI definition properties here
},
// Glob patterns pointing to your source files with JSDoc comments
sources: [path.join(__dirname, "src/routes/**/*.js")],
// Optional: Specify output path (defaults to 'swaggerSpec.json' in current dir)
// output: path.join(__dirname, 'public/api-docs.json'),
// Optional: Enable verbose logging
// verbose: true,
};
async function generateDocs() {
try {
const specification = await jsdocOpenApi(options);
console.log("OpenAPI specification generated successfully:");
// The specification object is returned, and also written to the output file if specified.
// console.log(JSON.stringify(specification, null, 2));
} catch (error) {
console.error("Error generating OpenAPI specification:", error);
}
}
generateDocs();
The package includes a Webpack plugin for seamless integration with frameworks like Next.js.
Create a helper file (e.g., with-open-api.js
) in your project root:
const path = require("node:path");
const fs = require("node:fs");
// Adjust the import path based on your project structure if needed
const { SwaggerCompilerPlugin } = require("@visulima/jsdoc-open-api");
/**
* @param {object} options
* @param {import('@visulima/jsdoc-open-api').SwaggerDefinition} options.definition - Base OpenAPI definition.
* @param {string[]} options.sources - Glob patterns for source files relative to project root.
* @param {boolean} [options.verbose=false] - Enable verbose logging.
* @param {string} [options.output='swagger/swagger.json'] - Output path relative to project root.
*
* @returns {function(import('next').NextConfig): import('next').NextConfig & {webpack: function(import('webpack').Configuration, object): import('webpack').Configuration}}
*/
const withOpenApi =
({ definition, sources, verbose, output = "swagger/swagger.json" }) =>
(nextConfig = {}) => {
return {
...nextConfig,
webpack: (config, options) => {
// Run generation only on the server build in Next.js
if (!options.isServer) {
return config;
}
let outputPath = output;
if (outputPath.startsWith("/")) {
outputPath = outputPath.slice(1);
}
if (!outputPath.endsWith(".json")) {
// Consider allowing YAML output as well?
throw new Error("The output path must end with .json");
}
const absoluteOutputPath = path.join(options.dir, outputPath);
const absoluteSourcePaths = sources.map((source) => path.join(options.dir, source.replace(/^\.\//, ""))); // Normalize paths
// Add the SwaggerCompilerPlugin to webpack plugins
config.plugins = config.plugins || [];
config.plugins.push(new SwaggerCompilerPlugin(absoluteOutputPath, absoluteSourcePaths, definition, { verbose }));
// Call the original webpack config function if it exists
if (typeof nextConfig.webpack === "function") {
return nextConfig.webpack(config, options);
}
return config;
},
};
};
module.exports = withOpenApi;
Wrap your Next.js configuration with the helper:
const withOpenApi = require("./with-open-api"); // Adjust path if necessary
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
env: {
NEXT_PUBLIC_APP_ORIGIN: process.env.VERCEL_URL || "http://localhost:3000", // Default to 3000?
},
// ... other Next.js config
};
module.exports = withOpenApi({
definition: {
openapi: "3.0.0",
info: {
title: "My Next.js API",
version: "1.0.0",
},
// servers: [{ url: '/api' }], // Optional: Define servers
},
// Paths relative to your project root
sources: ["pages/api/**/*.js", "src/controllers/**/*.js"],
output: "public/swagger.json", // Output to the public folder
verbose: false,
})(nextConfig);
Now, the OpenAPI specification (public/swagger.json
) will be generated automatically during your Next.js build.
When using the CLI generate
command without specifying paths or using the init
command, @visulima/jsdoc-open-api
looks for a .openapirc.js
file in your project root. This file should export an options object similar to the one used in Programmatic Usage:
// .openapirc.js
module.exports = {
definition: {
openapi: "3.0.0",
info: {
title: "API from Config",
version: "2.0.0",
},
// ... other base definition properties
},
// Array of glob patterns for your source files
sources: ["src/**/*.js", "routes/**/*.js"],
output: "docs/swagger.json", // Default output file path
verbose: false, // Default verbosity
};
You have two main ways to define your API specifications within JSDoc comments:
Embed standard OpenAPI 3.0 YAML or JSON directly within @openapi
or @swagger
blocks. The library extracts and merges these definitions.
/**
* @openapi
* components:
* schemas:
* User:
* type: object
* properties:
* id:
* type: integer
* format: int64
* example: 10
* username:
* type: string
* example: 'theUser'
* firstName:
* type: string
* example: 'John'
* lastName:
* type: string
* example: 'Doe'
* required:
* - id
* - username
*/
/**
* @openapi
* /users/{userId}:
* get:
* summary: Get user by ID
* description: Retrieve detailed information about a specific user.
* tags:
* - Users
* parameters:
* - name: userId
* in: path
* required: true
* description: ID of the user to retrieve.
* schema:
* type: integer
* format: int64
* responses:
* '200':
* description: Successful response with user data.
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/User' # Reference the schema defined above
* '404':
* description: User not found.
*/
function getUserById(userId) {
// Implementation...
}
Use custom JSDoc tags for a more concise way to define paths, operations, parameters, and responses.
Define the HTTP method and path, followed by tags like @summary
, @description
, @response
, etc.
/**
* GET /users
* @summary Returns a list of users.
* @description Optional extended description in CommonMark or HTML.
* @tags Users
* @response 200 - A JSON array of user names
* @responseContent {string[]} 200.application/json
*/
function listUsers() {
// Implementation...
}
Use @pathParam
, @queryParam
, @headerParam
, @cookieParam
to define parameters.
/**
* GET /users/{userId}
* @summary Returns a user by ID.
* @tags Users
* @pathParam {integer | int64} userId - The ID of the user to retrieve. {required}
* @queryParam {string} [role] - Filter users by role (optional). Possible values: 'admin', 'member'.
* @response 200 - OK
* @responseContent {User} 200.application/json - A user object (assuming 'User' schema is defined elsewhere).
*/
function getUser(userId, role) {
// Implementation...
}
Use @bodyContent
to describe the request body and @bodyRequired
if it's mandatory.
/**
* POST /users
* @summary Creates a new user.
* @tags Users
* @bodyContent {User} application/json - User object to create.
* @bodyRequired
* @response 201 - User created successfully.
* @responseContent {User} 201.application/json - The created user object.
*/
function createUser(userData) {
// Implementation...
}
Define responses using @response
for the status code and description, and @responseContent
for the body schema.
/**
* GET /products/{productId}
* @summary Get product details.
* @tags Products
* @pathParam {string} productId - ID of the product.
* @response 200 - Product details.
* @responseContent {ProductSchema} 200.application/json
* @response 404 - Product not found.
* @response default - Unexpected error.
*/
function getProduct(productId) {
// Implementation...
}
Reference schemas defined globally (usually using the standard @openapi
syntax in a central file or comment block) within your short syntax using type definitions like {User}
or {ProductSchema}
.
// Assuming 'User' schema is defined in components/schemas
/**
* PUT /users/{userId}
* @summary Update an existing user.
* @tags Users
* @pathParam {integer} userId - ID of the user to update.
* @bodyContent {User} application/json - Updated user data.
* @bodyRequired
* @response 200 - User updated successfully.
* @responseContent {User} 200.application/json
* @response 404 - User not found.
*/
function updateUser(userId, userData) {
// Implementation...
}
Reference securitySchemes
defined globally (using standard @openapi
syntax) with the @security
tag.
// Assuming 'BasicAuth' is defined in components/securitySchemes
/**
* GET /admin/settings
* @summary Get administrative settings (requires auth).
* @tags Admin
* @security BasicAuth
* @response 200 - Admin settings object.
*/
function getAdminSettings() {
// Implementation...
}
For detailed information on the short syntax tags and possibilities, please refer to the documentation (link to be added if available).
Contributions are welcome! Please refer to the Contribution Guidelines for details on how to submit pull requests, report issues, and suggest improvements.
This project is licensed under the MIT License. See the LICENSE.md file for details.