AI-Generated API Docs for Your Node.js App
Your Node.js API has 40 endpoints and the Swagger docs cover maybe 15 of them, half of which are already wrong. Nobody updates documentation on purpose — it just falls behind every sprint until a new developer or an external partner asks for the API spec and someone has to reverse-engineer it from the route files.
Why Manual API Documentation Always Falls Behind
Writing OpenAPI specs by hand means duplicating information that already exists in your code — route paths, request bodies, response shapes — in a separate YAML file that nobody remembers to touch during a refactor. The two sources drift apart within weeks. AI-generated API documentation flips this: instead of maintaining a parallel spec, you generate it directly from your actual route handlers and types, so it can never be more than one command behind reality.
How AI Can Generate OpenAPI Docs From Your Code
The pattern: extract your route definitions and any type information (TypeScript interfaces, Zod schemas, JSDoc comments) as plain text, feed that to an LLM with a prompt asking for a valid OpenAPI 3.0 spec, and write the result to a file your Swagger UI already serves.
Example: Generating an OpenAPI Spec From Express Routes
// generate-docs.js
import fs from "node:fs";
import { globSync } from "glob";
const routeFiles = globSync("src/routes/**/*.js");
const routeSource = routeFiles
.map((file) => fs.readFileSync(file, "utf-8"))
.join("\n\n");
const prompt = `Generate a valid OpenAPI 3.0 JSON spec for these
Express routes. Infer request/response shapes from the code.
Use realistic example values. Output only valid JSON, no prose.
${routeSource}`;
const response = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"x-api-key": process.env.ANTHROPIC_API_KEY,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
},
body: JSON.stringify({
model: "claude-sonnet-5",
max_tokens: 4096,
messages: [{ role: "user", content: prompt }],
}),
});
const result = await response.json();
const spec = JSON.parse(result.content[0].text);
fs.writeFileSync("openapi.json", JSON.stringify(spec, null, 2));
console.log("OpenAPI spec regenerated.");
Run this as a pre-commit hook, a CI step, or a manual npm run docs command — whichever fits how often your routes actually change. Point Swagger UI at the generated openapi.json and the docs update themselves every time the script runs.
Keeping Generated Docs Accurate Over Time
Generated docs are only as good as what the model can infer from your code, so a few things make a real difference: use TypeScript or Zod schemas instead of loosely-typed request handlers, since explicit types give the model far less to guess about; add JSDoc comments on routes with non-obvious behavior (auth requirements, rate limits, deprecated status) since the model can't infer intent it isn't told; and re-run generation in CI on every merge to main, not just when someone remembers, so drift never has a chance to accumulate.
Handling Authentication and Complex Response Shapes
Two areas trip up generated specs more than anything else: authentication schemes and deeply nested or conditional response bodies. For auth, don't rely on the model inferring your security scheme from middleware alone — explicitly document it in a short comment block near your route definitions (Bearer token, API key header, OAuth scopes required) so the generated spec's securitySchemes section is actually correct rather than a guess. For complex responses — a field that's sometimes an object and sometimes null, or a response shape that varies by user role — add a one-line comment describing the variation, since inferring conditional logic from runtime behavior alone is exactly the kind of thing a static code read will get wrong.
Common Mistakes Teams Make
- Generating once and never again. A one-time generated spec goes stale exactly like a hand-written one — the value is in re-running it automatically, not in the first run.
- Feeding the model your entire codebase. Scope the input to route files and their directly related types. A massive, unfocused prompt produces a vague, lower-quality spec and costs more per run.
- Skipping validation. Always validate the generated JSON against the OpenAPI schema before committing it — an LLM can produce syntactically broken specs, especially on large route sets.
- Not reviewing example values. Generated example request/response bodies are a best guess, not ground truth — a quick human pass catches obviously wrong examples before they mislead API consumers.
Best Practices
Treat the generation script as part of your build tooling, not a one-off script buried in a gist somewhere — check it into the repo, document how to run it, and wire it into CI. Diff the generated spec on every run so a reviewer can see exactly what changed in a PR, the same as any other generated artifact. And keep the prompt specific about output format (valid JSON only, no explanatory prose) so the pipeline step doesn't need extra parsing logic to strip commentary out.
Frequently Asked Questions
Will AI-generated docs be 100% accurate? Close, but not guaranteed — always validate the output and spot-check example values, especially for complex or unusual endpoints.
Does this replace writing good route code? No, it depends on it. Clear types and meaningful naming in your routes directly produce better generated documentation — this isn't a substitute for well-structured code.
What if my routes use a framework other than Express? The same pattern works for Fastify, Koa, or NestJS — only the code you extract and feed into the prompt changes, the generation approach stays the same.
Key Takeaways
AI-generated API documentation only works if it's wired into your actual development workflow — a script that runs on every merge, not a one-time favor someone does before a demo. Scope the input tightly, validate the output, and let your code stay the single source of truth instead of a YAML file that drifts away from it.
Is your API documentation actually current right now, or is it the thing everyone agrees to fix "next sprint"?