Skip to content

didrod205/apilint

🧩 apilint

Lint your OpenAPI specs for quality & consistency — zero-config, no browser.

npm version CI node license

A deterministic CLI that lints OpenAPI (Swagger) 3.x specs for design quality and consistency — broken $refs, missing responses/descriptions, duplicate operationIds, undeclared path params, REST naming, security gaps — with a score, A–F grade, and JSON/Markdown reports. Works on JSON and YAML, with a built-in parser (no heavyweight deps).


One-line summary

apilint reads your openapi.yaml/.json, runs 25+ opinionated quality rules, and reports issues with locations, fixes, and a score you can gate in CI — no config required, nothing uploaded.

Why this project exists

Your OpenAPI spec is the single source of truth for your API: docs, SDKs, mock servers, partner integrations and client code are all generated from it. But hand-written or code-generated specs drift into a mess:

  • A $ref points at a schema that was renamed — SDK generation breaks.
  • An endpoint has no documented response (or no error response) — consumers can't handle it.
  • Two operations share an operationIdgenerated client methods collide.
  • Paths like /getUserList/ mix verbs, casing and trailing slashes — an inconsistent API that's painful to use and impossible to standardize.

The tool everyone reaches for, Spectral, is powerful but has a real learning curve and ruleset configuration overhead. apilint is the opinionated, zero-config alternative: install, run, get a graded report. It's deterministic and static, so it drops straight into CI.

Key features

  • 🔗 Structure$ref integrity, OpenAPI version, paths present.
  • 🧱 OperationsoperationId presence/uniqueness, summaries, tags, and success and error responses.
  • 🧭 Parameters — every {templated} path segment must be declared; missing descriptions flagged.
  • 🏷️ Naming — REST conventions: no verbs in paths, kebab-case segments, no trailing slashes, operationId casing.
  • 🔐 Security — security schemes defined; operations require auth (toggle).
  • 📝 Docs quality — info metadata, response/parameter/schema descriptions.
  • 📊 Score + A–F grade per category and overall.
  • 📄 JSON & Markdown export, colored console output, CI gate exit codes.
  • 🧰 JSON + YAML input via a small built-in parser. Deterministic & offline.

Install

# run without installing
npx @didrod2539/apilint scan openapi.yaml

# or install
npm install -g @didrod2539/apilint    # global CLI (provides `apilint`)
npm install -D @didrod2539/apilint    # project dev-dependency (for CI)

Node ≥ 18. ESM + CJS + TypeScript types.

Quick start

apilint scan openapi.yaml
openapi.yaml  85/100 (B)  Messy API
  3 paths · 4 operations · 1 schemas · 0 tags
  Document structure    90
  Operations            74
  Parameters            70
  ...

  ✗ Broken $ref "#/components/schemas/MissingSchema" (paths./getUserList/.get…)
  ✗ Duplicate operationId "FetchProfile" (paths./user_profiles/{id}.post)
  ✗ Path parameter "{id}" in GET /user_profiles/{id} is not declared
  ⚠ Path "/getUserList/" has a trailing slash → Use "/getUserList".

Overall  85/100 (B)  7 error(s), 11 warning(s), 13 info

CLI usage

apilint scan [...targets]     # lint spec files or directories
apilint report <input.json>   # re-render a saved JSON report as Markdown
apilint init                  # scaffold apilint.config.json
apilint --help
apilint --version

scan options:

Option Description
--config <file> Path to a config file (otherwise auto-detected)
--json <file> Write a JSON report
--md <file> Write a Markdown report
--min-score <n> Exit non-zero if any spec scores below this (CI gate)
--quiet Hide info-level issues in the console

Pointed at a directory, scan finds files named like *openapi*/*swagger*/ *api*.{json,yaml,yml} recursively.

Example result

Full reports for the bundled sample spec are in examples/sample-report.md and examples/sample-report.json.

📸 Screenshot / demo GIF placeholder: ./docs/screenshot.png — record the terminal running npx @didrod2539/apilint scan examples/petstore-bad.yaml.

Configuration

Create apilint.config.json (or run apilint init):

{
  "requireSecurity": true,
  "requireTags": true,
  "operationIdStyle": "camelCase",
  "minScore": 80,
  "disableCategories": [],
  "disableRules": ["path-kebab-case"],
  "ruleSeverity": { "operation-tags": "warning" },
  "categoryWeights": { "structure": 1.4, "responses": 1.2 }
}
Field Meaning
requireSecurity Flag operations with no security (and no global default)
requireTags Flag untagged operations
operationIdStyle camelCase, snake_case, or any
minScore CI gate threshold (overridable with --min-score)
disableCategories Skip whole categories
disableRules Skip individual rules by id
ruleSeverity Override severity per rule id
categoryWeights Re-weight categories in the overall score

Categories: structure, info, paths, operations, parameters, responses, schemas, security, naming. See src/types.ts for the full rule-id list.

Real-world use cases

  1. Gate API quality in CI. Add apilint scan openapi.yaml --min-score 85. A PR that introduces a broken $ref or a duplicate operationId fails before it breaks SDK generation downstream.
  2. Standardize a team's API style. Set operationIdStyle and naming rules in apilint.config.json, commit it, and every new endpoint is held to the same conventions automatically.
  3. Audit an inherited or generated spec. Run apilint scan ./spec --md api-audit.md for a graded, per-category report of what's missing or inconsistent before you publish docs or a client SDK.

Programmatic API

import { analyze, toMarkdown } from "@didrod2539/apilint";

const report = analyze(yamlOrJsonText, config, { source: "openapi.yaml" });
console.log(report.score, report.grade, report.issues);
await fs.writeFile("api.md", toMarkdown(report));

Roadmap

  • More rules: example/requestBody coverage, response media types, enum/format hygiene, unused components, consistent error schema.
  • Resolve external $refs (other files / URLs, opt-in).
  • SARIF output for code-scanning integration.
  • A GitHub Action with PR annotations on changed operations.
  • Custom rule plugins and shareable config presets.
  • OpenAPI 3.1 / JSON Schema 2020-12 specific checks.

FAQ

Is this a Spectral replacement? For most teams' needs, yes — apilint ships an opinionated default ruleset with no configuration. Spectral is more extensible (custom DSL rules); apilint trades that for zero-config simplicity, a score/grade, and a tiny dependency footprint.

Does it need a network or a browser? No. It parses JSON/YAML with a built-in parser and runs entirely locally — no API key, no uploads.

Does it validate against the full OpenAPI JSON Schema? It focuses on high-value design-quality rules (the things that actually break SDKs, docs and consumers), not exhaustive schema validation. Use it alongside a strict validator if you need byte-level conformance.

Why a hand-written YAML parser? To stay dependency-light and deterministic. It supports the YAML subset OpenAPI specs use (block mappings/sequences, scalars, quotes, flow collections, block scalars). If your spec uses exotic YAML, convert to JSON.

My spec scored lower/higher than expected — can I tune it? Yes. disableRules, ruleSeverity, categoryWeights, and the require* toggles all change what's flagged; --min-score decides what fails CI.

Contributing

Contributions welcome! Each check is a small, self-contained rule in src/rules/. See CONTRIBUTING.md and the Code of Conduct.

git clone https://github.com/didrod205/apilint.git
cd apilint
npm install
npm test
npm run build
node dist/cli.js scan examples/petstore-bad.yaml

License

MIT © apilint contributors

💖 Sponsor

apilint is free, MIT-licensed, and built in spare time. If it caught a spec bug before it broke your SDK build, please consider supporting it:

Where your support goes: more rules, external $ref resolution, SARIF output, a PR-annotating GitHub Action, custom rule plugins, and fast issue responses.

About

Zero-config OpenAPI (Swagger) 3.x linter: broken $refs, duplicate operationIds, missing responses, undeclared path params, REST naming, security gaps. JSON+YAML, deterministic, runs in CI. A lightweight Spectral alternative.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors