Migrate from Redocly CLI
This guide moves a repository that lints and bundles its OpenAPI descriptions with Redocly CLI to
apigenie: the ruleset and the rules by name, redocly.yaml, your configurable rules, the
decorators, the bundle, the report in CI, and what stays with Redocly. It starts from Redocly CLI
2.72 with its recommended ruleset and an OpenAPI file, openapi.yaml.
You need the CLI installed; the Quickstart shows how. Keep Redocly CLI installed until the last step, so you can compare the two reports on the same files.
What changes and what stays
| Redocly CLI | API Genie | |
|---|---|---|
| Lint | redocly lint openapi.yaml |
apigenie lint openapi.yaml |
| Configuration | redocly.yaml: extends, rules, apis |
apigenie.yaml, section commands.lint (Configuration) |
| Built-in rulesets | minimal, recommended, recommended-strict, all, spec |
recommended, strict, all, per standard; 64 rules for OpenAPI |
| Severities | error, warn, off |
error, warning, hint, off |
| Configurable rules | rule/<name> with subject and assertions |
custom rules in Spectral’s format, given and then |
| Plugins | JavaScript rules, decorators and preprocessors | JavaScript functions, in a sandbox |
| Ignoring a problem | .redocly.lint-ignore.yaml |
x-apigenie-lint-disable in the document |
| Decorators | remove-x-internal, info-override, filter-in, … |
OpenAPI Overlays, applied by apigenie overlay |
| Bundle | redocly bundle openapi.yaml -o dist/openapi.yaml |
apigenie bundle openapi.yaml --output dist/openapi.yaml |
| Report formats | --format codeframe, stylish, json, junit, … |
--formatter stylish, json, junit, sarif, … |
| Exit status | 1 on an error, 0 on warnings alone | the same, and 2 on a file it cannot read |
| Fixes | none | --fix for the issues that have one |
| Configuration check | redocly check-config |
apigenie config check |
| Documentation | redocly build-docs openapi.yaml |
apigenie-generator docs openapi.yaml -o docs |
Run both on the same file
redocly lint --format stylish openapi.yaml
apigenie lint openapi.yaml
With its recommended ruleset, Redocly reports three problems in a small file whose operation
has no security requirement, no error response and an unused schema:
openapi.yaml:
15:5 error security-defined Every operation should have security defined on it or on the root level.
19:7 warning operation-4xx-response Operation must have at least one `4XX` response.
33:5 warning no-unused-components Component: "Unused" is never used.
API Genie reports ten:
3:3 error Info summary is missing or empty info-defined
3:3 error Info description is missing or empty info-defined
11:5 warning Tag 'pets' has no meaningful description defined tag-description-defined
16:7 error Operation has no meaningful description operation-description-defined
16:7 warning Security requirement is not defined operation-security-defined
21:11 warning Missing rate limiting header operation-rate-limiting-defined
27:19 error Object schema does not disable additional properties schema-no-additional-properties
30:23 error Schema with integer type does not define proper format schema-format-defined
34:7 warning String schema does not define constraints restricting its length schema-constraints
34:7 warning Unused shared component unused-shared-component
10 issues (5 errors, 5 warnings)
1 errors, 1 warnings are potentially auto-fixable
Each line gives the position, the severity, the message and the rule; every rule has a page in the
linter rules that says what it checks and why. The two reports differ, and not
only in the names: without configuration API Genie applies the
recommended ruleset, 43 rules that ask for
descriptions, formats and bounds Redocly’s recommended does not, and it leaves out some of what
Redocly reports, such as the missing error response. The next two sections say which.
Replace the configuration
A redocly.yaml that extends the built-in ruleset, adjusts a few rules and names the APIs:
extends:
- recommended
rules:
operation-4xx-response: off
no-unused-components: error
info-contact: warn
apis:
orders@v1:
root: apis/orders/openapi.yaml
becomes, in apigenie.yaml at the root of the repository:
version: '1.0'
commands:
lint:
extends: [recommended]
rules:
unused-shared-component: error
contact-defined: warning
extendsnames API Genie’s rulesets, not Redocly’s.recommendedis the default;strictturns on more rules with higher severities,allevery rule. Redocly’srecommended-strictisrecommendedwith every rule aterror, which has no ruleset of its own: start fromrecommendedand raise the rules that matter toerror.minimalisrecommendedwith most rules off, andspec, thestructrule alone, is openapi-json-schema-validation listed underruleswithoutextends.- A rule takes its name from the tables below. Redocly’s
warniswarning;errorandoffstay. - A rule with no counterpart, such as
operation-4xx-response, has no line. apishas no counterpart: onecommands.lintsection applies to every file the command is given. A repository whose APIs need different rules keeps a configuration file per API and passes it with--config, or disables rules in the documents, as below.oas2Rules,oas3_0Rules,oas3_1Rulesandasync3Rulesbecome theswaggerandasyncapisections next torules: an OpenAPI 3.x file, a Swagger 2.0 file and an AsyncAPI file are linted by three linters with rules of their own, from one configuration (configuration of lint).arazzo1Ruleshave no counterpart: Arazzo files are not read.--skip-ruleon the command line isoffin the configuration, and--extendsis--configwith another file.--max-problemshas no counterpart.
The rules of recommended, by name
The rules Redocly’s recommended ruleset reports as errors, and their counterparts in the OpenAPI
linter. A rule marked not checked has no counterpart today: drop its line from the
configuration.
| Redocly | API Genie | Note |
|---|---|---|
struct |
openapi-json-schema-validation | |
no-unresolved-refs |
openapi-json-schema-validation | local schema $ref targets are checked; external references are not fetched |
operation-operationId-unique |
operation-id-unique | |
operation-parameters-unique |
parameters-unique | |
path-parameters-defined |
path-parameters-defined | path-parameters-on-items asks for them on the path item |
security-defined |
operation-security-defined | every operation has a security requirement |
no-identical-paths |
paths-unique | |
no-path-trailing-slash, path-declaration-must-exist |
paths-well-formed | also rejects // and upper-case letters outside the placeholders |
path-not-include-query |
not checked | |
no-enum-type-mismatch |
schema-enum-types | |
no-schema-type-mismatch, no-example-value-and-externalValue |
not checked | |
no-empty-servers |
servers-defined | |
no-server-trailing-slash, no-server-variables-empty-enum, no-undefined-server-variable |
not checked | server-urls checks the scheme and the case of the URL instead |
operation-summary |
not checked | the custom rule below |
operation-operationId-url-safe, spec-components-invalid-map-name |
not checked |
The rules it reports as warnings:
| Redocly | API Genie | Note |
|---|---|---|
info-license, info-license-strict |
license-defined | asks for name, and url or identifier |
no-ambiguous-paths |
paths-unique | |
no-duplicated-enum-values |
schema-enum-no-duplicates | |
no-duplicated-tag-names |
tags-unique | |
no-required-schema-properties-undefined |
schema-required-properties-defined | schema-no-contradictions adds the case of additionalProperties: false |
no-unsafe-markdown |
safe-markdown | |
no-unused-components |
unused-shared-component | follows references transitively, so a component used only by an unused one is reported too |
operation-2xx-response |
operation-success-response | |
operation-4xx-response |
not checked | standard-response-errors checks the format of the error responses that are there |
operation-operationId |
operation-id-defined | |
tag-description |
tag-description-defined | |
no-invalid-media-type-examples, no-invalid-parameter-examples, no-invalid-schema-examples |
not checked | examples are not validated against their schema |
no-illogical-composition-keywords, no-mixed-number-range-constraints |
not checked | schema-no-contradictions reports a schema that rejects every value, schema-discriminator-defined a oneOf without discriminator |
no-server-example.com, security-scopes-defined, spec-ref-siblings |
not checked |
The rules Redocly leaves off by default:
| Redocly | API Genie |
|---|---|
info-contact |
contact-defined |
operation-description |
operation-description-defined |
parameter-description |
parameter-description-defined |
path-params-defined |
path-parameters-defined |
tags-alphabetical |
tags-sorted |
request-mime-type, response-mime-type |
standard-media-types, which checks that the media types are registered ones rather than a list of yours |
required-string-property-missing-min-length |
schema-constraints |
scalar-property-missing-example |
schema-example-defined |
operation-4xx-problem-details-rfc7807 |
standard-response-errors |
response-contains-header |
not checked; operation-rate-limiting-defined asks for the rate-limiting headers |
component-name-unique, no-http-verbs-in-paths, operation-singular-tag, operation-tag-defined, paths-kebab-case, path-http-verbs-order, path-segment-plural, boolean-parameter-prefixes, array-parameter-serialization, response-contains-property, spec-strict-refs, spec-example-values |
not checked |
The oas2Rules apply to Swagger 2.0 files, which API Genie lints with the
Swagger 2.0 linter: struct is
swagger-validation, which also reports the
unresolved references, and the rules that share a name with an OpenAPI rule check the same thing.
The async3Rules map onto the AsyncAPI linter the same way.
What the recommended ruleset adds
Rules of recommended that Redocly’s has nothing for; each has a page that says what it checks
and why:
- info-defined, operation-description-defined, parameter-description-defined and tag-description-defined: the texts a reader of the documentation needs, and they have to say something.
- schema-format-defined, schema-format-type-mismatch and schema-format-deprecated: numbers and strings say their format, and the format fits the type.
- schema-constraints and schema-no-additional-properties: strings, numbers, arrays and objects have bounds.
- schema-no-contradictions,
schema-oneof-no-overlap and
schema-conditional-effective: schemas
that reject every value,
oneOfbranches a value matches twice,ifwithout effect. - standard-response-codes, unambiguous-response-codes and no-content-response-defined: the responses an operation declares.
- operation-rate-limiting-defined, paths-max-depth, paths-max-count, parameter-naming and schema-datetime-suffix: the headers, the shape of the URLs and the names.
Outside recommended: spell-check for the texts written
for humans, schema-keyword-support for the
JSON Schema keywords the tools around the document ignore, and the
privacy ruleset for credentials and personal data in
URLs. extends: [recommended, privacy] adds the last one.
Carry your configurable rules over
A configurable rule of redocly.yaml names the nodes it checks with subject and what it asserts
about them:
rules:
rule/operation-summary:
subject:
type: Operation
property: summary
assertions:
defined: true
severity: error
message: Operations must have a summary
It becomes a custom rule under commands.lint.rules,
in the format of Spectral: a JSONPath expression selects the nodes, a function checks each of
them:
version: '1.0'
commands:
lint:
extends: [recommended]
rules:
operation-summary:
description: Operations must have a summary
message: "{{property}} is missing at {{path}}"
severity: error
given: "$.paths[*][get,put,post,delete,options,head,patch,trace]"
then:
field: summary
function: truthy
subject.typebecomes thegivenexpression that selects the same nodes,subject.propertythefield, andsubject.filterInParentKeysa member union in the expression. Awherecondition becomes a JSONPath filter (JSONPath).- The assertions map onto the core functions:
definedistruthyordefined,patternandnotPatternarepatternwithmatchornotMatch,enumisenumeration,casingiscasing,minLengthandmaxLengtharelength,mutuallyExclusiveisxor,sortOrderisalphabetical.required,disallowed,requireAny,mutuallyRequired,nonEmptyandrefhave no function: write a JavaScript function of a few lines. severityandmessagestay;{{property}},{{path}}and{{value}}fill the message.
A rule of a custom plugin is a JavaScript visitor over the document’s node types; it is rewritten
as a custom rule whose function is a JavaScript module in functions/ next to apigenie.yaml.
Functions run in a sandbox with no file system, network, processes or timers, and a call must
finish within 5 seconds. The decorators and preprocessors of a plugin become overlays, next.
Replace the decorators with overlays
Decorators change the document on the way to the bundle and the documentation: remove-x-internal
drops what is marked internal, info-override and filter-in or filter-out edit and select.
API Genie writes these changes as an OpenAPI Overlay, a file of
actions that each select nodes with a JSONPath query and change them:
overlay: 1.0.0
info:
title: Remove the internal operations
version: 1.0.0
actions:
- target: $.paths[*][?(@["x-internal"] == true)]
remove: true
- target: $.paths[?(@["x-internal"] == true)]
remove: true
- target: $.info
update:
title: Public API
description: The public operations only.
apigenie overlay --overlay public.overlay.yaml openapi.yaml --output dist/openapi.yaml
The first two actions remove the operations and the path items marked x-internal: true, the
third edits info; YAML comments of the input are kept. The code generators take an overlay
directly, with --overlay or the overlay setting of a target
(Overlays), so the public version of the document need not
be written to disk for them.
Bundle
redocly bundle openapi.yaml -o dist/openapi.yaml
apigenie bundle openapi.yaml --output dist/openapi.yaml
Both copy the schemas, parameters and responses of other local files into components, named
after their files, and rewrite the references; the extension of the output file picks JSON or
YAML. bundle does not keep YAML comments, and references by URL are
not supported. --dereferenced, --remove-unused-components, --keep-url-references, --ext
and --metafile have no counterpart, and decorators don’t run during the bundle: apply the
overlay to the bundled file in a second command.
Disable a rule in one place
Redocly keeps the problems to ignore in .redocly.lint-ignore.yaml, written by
--generate-ignore-file. API Genie turns the rule off where the issue is, in the document, with
x-apigenie-lint-disable on the object and its descendants:
paths:
/legacy/export:
x-apigenie-lint-disable:
- operation-id-defined
get:
summary: Export, as it was
Disable a rule as close to the issue as possible; disabling rules says more.
The report in CI
The formats that keep their name: --format stylish, json, checkstyle and junit become
--formatter stylish, json, checkstyle and junit. API Genie adds sarif, html,
compact, tap, unix and visualstudio; Redocly’s codeframe (its default), codeclimate,
summary, markdown and github-actions have no counterpart. For GitLab, junit is what the
merge request reads; for GitHub code scanning, sarif
(formatters). The exit status stays what it was: 1 when an
error is reported, 0 on warnings alone (exit status).
On GitHub Actions, the run step with --format github-actions becomes the
GitHub Action, which installs the CLI and shows the issues on the lines
of the pull request:
on: pull_request
jobs:
api:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mykulyak/api-genie-action@v0
with:
command: lint
files: openapi.yaml
What stays with Redocly
push,project,preview,login,ejectandtranslatework with the Redocly platform and its projects.build-docsbecomesapigenie-generator docs, a static site with search and Try it out, built with npm and served from any static host.splitandjoinhave no counterpart;apigenie bundlegoes one way.generate-clientbecomesapigenie-generator client fetch, anddiffbecomesapigenie diff; Migrate from oasdiff covers the move of a breaking-change check in detail.respectandgenerate-arazzorun and write Arazzo workflows, which are not read;apigenie testchecks a running server against the description with tests of its own format.proxy,driftandgenerate-specwork on recorded traffic. The validating proxy ofapigenie-serverchecks live traffic against the description; inferring a description from traffic has no counterpart.stats,scoreandscorecard-classichave no counterpart.
Remove Redocly CLI
When the two reports agree on what matters to you: delete redocly.yaml and
.redocly.lint-ignore.yaml, remove @redocly/cli from the development dependencies, and replace
the Redocly step of the pipeline with the one above. The fixes the linter offers are a --fix
away:
apigenie lint --fix openapi.yaml