Detects stylistic and structural issues in OpenAPI schemas, improving their quality.

Usage

apigenie lint [OPTIONS] FILES

Description

The OpenAPI linter helps developers and teams create high-quality, consistent, and well-structured schemas. It achieves this by validating schemas against a set of configurable lint rules.

Lint Rules

Each rule in the linter focuses on a specific aspect of an OpenAPI schema. Here are some examples:

  • operation-description-defined: Ensures that all operations have meaningful descriptions.
  • operation-success-response: Ensures that all operations define a success response (e.g. 201 Created).
  • paths-max-count and paths-max-depth: Limit API complexity by checking the number of path items and depth (e.g. a number of segments) or URLs.

Each rule can have a severity level assigned, indicating its importance. Possible values for severity are warning and error. Both warnings and errors show up in the linter output, but only errors prevent the linter check from succeeding.

Some rules may accept options that adjust how they evaluate the schema.

The API Genie linter currently offers 53 built-in rules, with over 20 additional rules under active development.

Rulesets

To simplify configuration and provide more flexibility, rules can be combined into rulesets. A ruleset is a named group of rules with assigned severity levels and options.

Disabling certain rules

There might be situations where you want to temporarily disable a rule for a specific part of a schema. This might be due to a legacy issue, ongoing development, or a specific API decision. To do this, annotate parts of your OpenAPI schema with the x-apigenie-lint-disable extension. The value of this extension must be a list of rule names you want to disable.

Rules can be disabled on any schema object, including OpenAPI object itself. Disabling a rule on specific schema object applies to that object and its descendants within the schema hierarchy.

For example, in the snippet below, the contact-defined rule is disabled on the Info schema object. However, it will also be enforced on the nested Contact object because Contact is a descendant of Info within the schema structure.

info:
  x-apigenie-lint-disable:
    - contact-defined

A couple of final remarks:

  • Disable rules as close to the problematic point in the schema as possible.
  • Disabling linter rules should be an exception, not the rule.

Autofixing

Some issues found by the apigenie lint command can be automatically fixed. To do this, run the command with the --fix option.

Formatting results

Apart from rules, API Genie linter allows to customize the way it displays results. It ships with several built-in formatters, described below, in subsections.

Formatters differ in the way they present data, but all of them sort issues by:

  1. The line in the input OpenAPI schema file where they were found
  2. Severity level: warnings are displayed before errors.

Note: If you used ESLint you may notice that the list of formatters API Genie provides is close to that of ESLint. This is by no coincidence, as both tools aim to be usable in many different environments.

checkstyle

Outputs results in the Checkstyle format.

<?xml version="1.0" encoding="utf-8"?>
<checkstyle version="4.3">
    <file name="/apigenie/data/openapi.yaml">
        <error line="2" column="2" severity="error" message="Info summary is missing or empty" source="info-defined"/>
        <error line="12" column="4" severity="warning" message="Tag &apos;Articles&apos; has no meaningful description defined" source="tag-description-defined"/>
        <error line="13" column="4" severity="warning" message="Tag &apos;Comments&apos; has no meaningful description defined" source="tag-description-defined"/>
        <error line="14" column="4" severity="warning" message="Tag &apos;Favorites&apos; has no meaningful description defined" source="tag-description-defined"/>
        <error line="15" column="4" severity="warning" message="Tag &apos;Profile&apos; has no meaningful description defined" source="tag-description-defined"/>
    </file>
</checkstyle>

compact

Mimicks the default output of JSHint.

/apigenie/data/openapi.yaml: line 2, col 2, Error - Info summary is missing or empty. (info-defined)
/apigenie/data/openapi.yaml: line 12, col 4, Warning - Tag 'Articles' has no meaningful description defined. (tag-description-defined)
/apigenie/data/openapi.yaml: line 13, col 4, Warning - Tag 'Comments' has no meaningful description defined. (tag-description-defined)
/apigenie/data/openapi.yaml: line 14, col 4, Warning - Tag 'Favorites' has no meaningful description defined. (tag-description-defined)
/apigenie/data/openapi.yaml: line 15, col 4, Warning - Tag 'Profile' has no meaningful description defined. (tag-description-defined)

html

Prints results as a single HTML file. Issues are displayed in a table, every issue takes one table row.

<!DOCTYPE html>
<html>
<body>
  <section id="overview">
    <h1>API Genie Report</h1>
    <ul>
      <li>Total: 224</li>
      <li>Errors: 32</li>
      <li>Warnings: 192</li>
    </ul>
  </section>
  <section id="issues">
    <table>
      <caption>/apigenie/data/openapi.yaml</caption>
      <tr>
        <td class="pos">2:2</td>
        <td class="error">Error</td>
        <td>Info summary is missing or empty</td>
        <td>
          <a href="https://apigenie.pl/techdocs/linter/rules/info-defined">info-defined</a>
        </td>
      </tr>
      <tr>
        <td class="pos">12:4</td>
        <td class="warning">Warning</td>
        <td>Tag 'Articles' has no meaningful description defined</td>
        <td>
          <a href="https://apigenie.pl/techdocs/linter/rules/tag-description-defined">tag-description-defined</a>
        </td>
      </tr>
    </table>
</body>
</html>

json

Outputs lint results in JSON file. This format is useful if you want to process linter result programmatically.

[
  {
    "filePath": "/apigenie/data/openapi.yaml",
    "messages": [
      {
        "column": 2,
        "line": 2,
        "message": "Info summary is missing or empty",
        "ruleId": "info-defined",
        "severity": "error"
      },
      {
        "column": 4,
        "line": 12,
        "message": "Tag 'Articles' has no meaningful description defined",
        "ruleId": "tag-description-defined",
        "severity": "warning"
      },
      ... more issues ...
    ]
  }
]

junit

Outputs results to format compatible with the JUnit Jenkins plugin.

<?xml version="1.0" encoding="utf-8"?>
<testsuites>
  <testsuite package="apigenie" time="0" tests="224" errors="224" name="/apigenie/data/openapi.yaml">
    <testcase time="0" name="apigenie.info-defined" classname="apigenie.info-defined">
      <failure message="Info summary is missing or empty"><![CDATA[line 2, col 2, Error - Info summary is missing or empty. (info-defined)]]></failure>
    </testcase>
    <testcase time="0" name="apigenie.tag-description-defined" classname="apigenie.tag-description-defined">
      <failure message="Tag &apos;Articles&apos; has no meaningful description defined"><![CDATA[line 12, col 4, Warning - Tag 'Articles' has no meaningful description defined. (tag-description-defined)]]></failure>
    </testcase>
    <testcase time="0" name="apigenie.tag-description-defined" classname="apigenie.tag-description-defined">
      <failure message="Tag &apos;Comments&apos; has no meaningful description defined"><![CDATA[line 13, col 4, Warning - Tag 'Comments' has no meaningful description defined. (tag-description-defined)]]></failure>
    </testcase>
  </testsuite>
</testsuites>

stylish

This is the default formatter. It presents result as table, with values being highligted in different colors.

  764:6   warning  Unused shared component                                              unused-shared-component
  769:12  warning  Object schema does not define constraints restricting its size       schema-constraints
  769:12  error    Object schema does not disable additional properties                 schema-no-additional-properties
  777:6   warning  Unused shared component                                              unused-shared-component
  781:8   error    Schema with integer type does not define proper format               schema-format-defined
  781:8   warning  Integer schema does not define constraints restricting its range     schema-constraints
  785:6   warning  Unused shared component                                              unused-shared-component
  789:8   error    Schema with integer type does not define proper format               schema-format-defined
  789:8   warning  Integer schema does not define constraints restricting its range     schema-constraints
  795:6   warning  Unused shared component                                              unused-shared-component

  224 issues (32 errors, 192 warnings)
  0 errors, 6 warnings are potentially auto-fixable

tap

Outputs results to the Test Anything Protocol (TAP) specification format.

TAP version 14
1..1
not ok - /apigenie/data/openapi.yaml
  ---
  errorCount: 32
  issues:
    - column: 2
      line: 2
      message: Info summary is missing or empty
      ruleId: info-defined
      severity: error
    - column: 4
      line: 12
      message: Tag 'Articles' has no meaningful description defined
      ruleId: tag-description-defined
      severity: warning
    - column: 4
      line: 13
      message: Tag 'Comments' has no meaningful description defined
      ruleId: tag-description-defined
      severity: warning

unix

Outputs results to a format similar to many commands in UNIX-like systems. If you use grep or awk, this format may be best for you.

/apigenie/data/openapi.yaml:2:2: Info summary is missing or empty. [Error/info-defined]
/apigenie/data/openapi.yaml:12:4: Tag 'Articles' has no meaningful description defined. [Warning/tag-description-defined]
/apigenie/data/openapi.yaml:13:4: Tag 'Comments' has no meaningful description defined. [Warning/tag-description-defined]
/apigenie/data/openapi.yaml:14:4: Tag 'Favorites' has no meaningful description defined. [Warning/tag-description-defined]
/apigenie/data/openapi.yaml:15:4: Tag 'Profile' has no meaningful description defined. [Warning/tag-description-defined]
/apigenie/data/openapi.yaml:16:4: Tag 'Tags' has no meaningful description defined. [Warning/tag-description-defined]

visualstudio

Outputs results to format compatible with the integrated terminal of the Visual Studio IDE.

/apigenie/data/openapi.yaml(2,2): error info-defined : Info summary is missing or empty.
/apigenie/data/openapi.yaml(12,4): warning tag-description-defined : Tag 'Articles' has no meaningful description defined.
/apigenie/data/openapi.yaml(13,4): warning tag-description-defined : Tag 'Comments' has no meaningful description defined.
/apigenie/data/openapi.yaml(14,4): warning tag-description-defined : Tag 'Favorites' has no meaningful description defined.
/apigenie/data/openapi.yaml(15,4): warning tag-description-defined : Tag 'Profile' has no meaningful description defined.
/apigenie/data/openapi.yaml(16,4): warning tag-description-defined : Tag 'Tags' has no meaningful description defined.

Options

—config FILE

Optional path to the configuration file. If not specified, the default configuration is used. For details, see the configuration section.

—fix

If possible, automatically fixes problems it finds. Modified file is written under the same name as the original.

—formatter NAME

Sets the formatter to display the linter result. Supported formatter names are:

  • checkstyle
  • compact
  • html
  • json
  • junit
  • stylish - the default formatter
  • tap
  • unix
  • visualstudio

Configuration

The linter stores its configuration under the #/commands/linter key in the configuration file. See the global configuration section to understand how this file is structured.

The linter configuration allows to apply rulesets, enable or disable certain rules, modify rule severity levels, or modify rules’ options.

Example: a minimal confiration illustrating all possible variants of configuring rules.

version: 1.0
commands:
  lint:
    extends:
      - recommended
      # ... more rulesets to extend from ...
    rules:
      info-defined: off
      paths-max-count:
        - error
        - 30
      schema-datetime-suffix:
        - error
        - At
      tags-unique: error
      # ... more rules ...

If the configuration file is not specified, linter uses the default configuration:

version: 1.0
commands:
  lint:
    extends:
      - recommended

lint.extends

This block lists rulesets whose configuration will be used and combined to create the final set of rules, rule severity levels and options.

The value of this block, if present, must be an array of supported ruleset names. Linter will read all rulesets’ configurations, in the order they are listed. If two rulesets contain the same rule, linter uses the configuration from the ruleset that was specified later in the list.

lint.rules

These are overrides to the rules’ configurations from rulesets.

If present, value of this block must be a map. Keys of the map must be valid rule names, and values can be either strings or two-element arrays.

For valid rule names see the rule index page.

lint.rules.RULE_ID

Such blocks configure a rule named RULE_ID. Each block may be a string or a two-element array.

  • String: If it a string, and must be one of:
    • off - to disable rule
    • warning - to set rule severity to warning
    • error - to set rule severity to error
  • Array: If it is an array, it must contain two elements:
    • The first element must be a valid rule severity (either warning or error).
    • The second element is rule-specific value, containing rule’s options.

See the documentation of each rule to find what options it accepts.

Examples

  • Disables the info-defined rule:
version: 1.0
commands:
  lint:
    rules:
      info-defined: off
  • configure the paths-max-count rule to issue an error when the number of path items is larger than 30. If the number is below or equal to 30, the rule does not produce an error or warning.
version: 1.0
commands:
  lint:
    rules:
      paths-max-count:
        - error
        - 30

See Also