Aliases

An alias gives a name to one or more JSONPath expressions, so several rules can share the same selector. Write the path once, in one place, and when the document format changes you fix it there instead of in every rule.

This page describes how aliases work in OpenLint today. Every example was run against OpenLint 1.0.0. The formal definition is in the specification, under aliases and selecting nodes.

Declaring and using an alias

Declare aliases under aliases at the root of the ruleset. A simple alias is a list of path expressions. A rule refers to it from given with a leading #:

aliases:
  PathItem:
    - $.paths[*]
rules:
  path-item-has-summary:
    given: "#PathItem"
    then:
      field: summary
      function: truthy

Quote "#PathItem". In YAML an unquoted # starts a comment.

Names

An alias name starts with a letter, followed by letters, digits, _ and -. A name like 1st-param makes the ruleset invalid:

to avoid confusion the name must match /^[A-Za-z][A-Za-z0-9_-]*$/ regular expression

Building on an alias

After the name you can carry on with more path, so one alias serves many rules:

given: "#PathItem.get"                 # one operation
given: "#PathItem[get,put,post]"       # several
given: "#Servers.url"                  # a field of each match

An alias can also be built from other aliases. These are the aliases the built-in spectral:oas ruleset declares:

aliases:
  PathItem:
    - $.paths[*]
  OperationObject:
    - "#PathItem[get,put,post,delete,options,head,patch,trace]"
  SecurityRequirementObject:
    - $.security[*]
    - "#OperationObject.security[*]"

An alias can’t refer to itself, directly or through other aliases. OpenLint rejects the ruleset:

Alias "A" is circular. Resolution stack: A -> B -> A

Several paths in one alias

List every place a thing can appear, and a rule using the alias checks all of them. This alias selects every servers entry OpenAPI 3 allows, which the built-in oas3-server-* rules don’t (they only check the top level):

aliases:
  Servers:
    - $.servers[*]
    - $.paths[*].servers[*]
    - $.paths[*][get,put,post,delete,options,head,patch,trace].servers[*]
    - $..callbacks[*][*].servers[*]
    - $..callbacks[*][*][get,put,post,delete,options,head,patch,trace].servers[*]
rules:
  server-https:
    message: " must use https"
    given: "#Servers.url"
    then:
      function: pattern
      functionOptions:
        match: "^https://"

Listing the locations is more precise than $..servers, which also matches any property named servers in a schema or an example.

Scoped aliases: one name, different paths per format

The same thing often lives in different places in different versions of a format. A scoped alias picks its paths by the format of the document being linted. It’s an object with targets, and each target has formats and given. An optional description explains it.

aliases:
  ParameterObject:
    description: Reusable parameters, wherever this version of OpenAPI keeps them.
    targets:
      - formats: [oas2]
        given:
          - $.parameters[*]
      - formats: [oas3]
        given:
          - $.components.parameters[*]
  ParameterName:
    - "#ParameterObject.name"
rules:
  parameter-name-flat:
    formats: [oas2, oas3]
    given: "#ParameterName"
    then:
      function: casing
      functionOptions:
        type: flat

On an OpenAPI 3 document this reports components.parameters.P.name, and on Swagger 2.0 parameters.P.name. Things to know:

Where aliases don’t reach

Aliases belong to the ruleset that declares them. That has three consequences that often surprise people:

1. You can’t use an extended ruleset’s aliases. spectral:oas declares OperationObject, but extending it doesn’t make the alias available to your rules:

extends: [[spectral:oas, "off"]]
rules:
  my-rule:
    given: "#OperationObject"     # fails
    then:
      field: summary
      function: truthy
Alias "OperationObject" does not exist

Copy the aliases you need into your own ruleset.

2. An inherited rule keeps its own ruleset’s aliases. A rule from spectral:oas resolves its aliases against spectral:oas, even if your ruleset declares an alias with the same name.

3. An alias in an override only reaches the rules that override defines. Declaring an alias with the same name in an override doesn’t change the rules defined at the root, even for the files the override matches:

aliases:
  T:
    - $.info.title
rules:
  r:
    given: "#T"
    then:
      function: falsy
overrides:
  - files: ["api.yaml"]
    aliases:
      T:
        - $.info.version    # has no effect on rule r

Rule r still checks info.title in api.yaml. These limits are open questions in the specification and discussion #2.

YAML gotcha: quote paths in flow lists

In a flow-style list, [ ... ], a path containing [*] breaks the YAML, and OpenLint reports a confusing error (“Ruleset must have rules or extends or overrides defined”). Use a block list, or quote the path:

given: ["$.components.parameters[*]"]   # works
given: [$.components.parameters[*]]     # breaks the ruleset

Summary

You can You can’t
Name one or many paths and use them from given with # Use an alias declared in a ruleset you extend
Continue the path after the name (#PathItem.get) Change an inherited rule’s aliases
Build aliases from other aliases Make an alias refer to itself
Pick paths per format with a scoped alias Reach the root rules with an alias declared in an override
Declare aliases at the root or in a file-scoped override Share aliases between rulesets, yet: there’s no alias registry