Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Returning multiple rule violations on same path #1299

Closed
radicarl opened this issue Aug 3, 2020 · 3 comments
Closed

Returning multiple rule violations on same path #1299

radicarl opened this issue Aug 3, 2020 · 3 comments
Labels
t/bug Something isn't working

Comments

@radicarl
Copy link

radicarl commented Aug 3, 2020

Describe the bug
We have a custom rule checking the naming convention in paths. The function checks if a path segment is

  • a fixed value like /my-resource
  • a variable like {myVariable}
  • or mixed like /my-resource-{myVariable}

We implemented a custom function and not just a complex regex to provide the developer with a exact error message. In Spectral 4.5.0 we could return the following messages for the path /total_invalid/Path/{WithInvalid}/{pathPARAMS}:

  1. total_invalid must be in lower-kebab-case.
  2. Path must be in lower-kebab-case.
  3. {WithInvalid} must be in lowerCamelCase.
  4. {pathPARAMS} must be in lowerCamelCase.

With 5.4.0 we get only the first message because of the elemination of violations of the same type on the same element.

I read Issue #1030 and #920 and also read https://github.com/stoplightio/spectral/blob/develop/docs/guides/5-custom-functions.md#returning-multiple-results, but could not getting it work.

The problem I have, is that rule and path (/total_invalid/Path/{WithInvalid}/{pathPARAMS}) is always the same, only the message changes. I tried to use only partial parts like paths./total_invalid/, paths./total_invalid/Path/, paths./total_invalid/Path/{WithInvalid} and paths./total_invalid/Path/{WithInvalid}/{pathPARAMS}. When I do this, I get the first and the forth expected message.
I also tried random paths, but in this case I get only the first message. Looks like the path i proivde in the result of the function must exists in the oas document? Could not find anything about that in the documentation.

To Reproduce
.spectral.yml

extends: spectral:oas

functions:
  - pathNaming

rules:
  naming-paths:
    description: "Path must be named in lower-kebab-case and path variables must be lowerCamelCase."
    message: "{{error}}"
    severity: 0
    given: $.paths
    then:
      field: "@key"
      function: pathNaming

funtions/pathNaming.js

module.exports = (path, opts) => {
    const regexPathVariable = "\\{_?[a-z]+((\\d)|([A-Z0-9][a-z0-9]+))*([A-Z])?\\}";
    const regexPath = "[a-z0-9]+(-[a-z0-9]+)*";
    const regexMixed = "^" + regexPath + "(-" + regexPathVariable + ")?$";
    let pathParts = path.split("/");
    pathParts.shift();

    let messages = [];
    let pathRebuild = "";
    for (let part of Object.values(pathParts)) {
        pathRebuild += "/" + part;
        if (part === "") {
            continue;
        }
        if (part.startsWith("{") && part.endsWith("}")) {
            if (!part.match("^" + regexPathVariable + "$")) {
                messages.push({
                    message: "`" + part + "` must be in lowerCamelCase",
                    path: ["paths", pathRebuild] },
                );
            }
        } else if (part.endsWith("}")) {
            if (!part.match(regexMixed)) {
                messages.push({
                    message: "In `" + part + "` the path part mus be lower-kebab-case and the path variable must be lowerCamelCase.",
                    path: ["paths", pathRebuild] },
                );
            }
        } else if (!part.match("^" + regexPath + "$")) {
            messages.push({
                message: "`" + part + "` must be in lower-kebab-case.",
                path: ["paths", pathRebuild] },
            );
        }
    }

    // if I return this, the message contains all four messages with different path array
    //return [{message: JSON.stringify(messages)}];
    return messages;
};

openapi.yml

openapi: 3.0.2
info:
  title: My Title
  version: 0.1.0
  description: Lorem Impsum

servers:
  - url: https://example.org/api/

tags:
  - name: MyTag

paths:
   /total_invalid/Path/{WithInvalid}/{pathPARAMS}: {}
@radicarl radicarl added the t/bug Something isn't working label Aug 3, 2020
@radicarl
Copy link
Author

radicarl commented Aug 4, 2020

Another Example:

.spectral.yml

extends: spectral:oas

functions:
  - deprecatedHeader

rules:
  deprecated-header:
    description: If request, parameters or response contains deprecated elements, a Warning-Header should be sent with the response.
    message: "Missing Warning header on {{error}}."
    recommended: true
    severity: 1
    given: $.paths
    then:
      function: deprecatedHeader

functions/deprecatedHeader.js

module.exports = (paths, opts) => {
    return [
        {
            message: "paths./all-deprecated-only-one-msg.put.200",
            path: ["paths","/all-deprecated-only-one-msg","put","200"]
        },{
            message: "paths./all-deprecated-only-one-msg.put.201",
            path: ["paths","/all-deprecated-only-one-msg","put","201"]
    }];
}

openapi.yml

openapi: 3.0.2
info:
  title: Raumbuchungs-API
  version: ${project.version}
  description: API für das Buchen und Verwalten von Besprechungsräumen.
  contact:
    name: API-Team
    email: [email protected]


servers:
  - url: https://api.gateway.de

tags:
  - name: MyTag

paths:
  /all-deprecated-only-one-msg:
    put:
      description: "Deprecated: Operation an der Request, Params, und Response deprecated sind. Jede Response soll aber nur einmal bemängelt werden."
      deprecated: true
      operationId: putAllDeprecatedOnlyOneMsg
      tags:
        - MyTag
      parameters:
        - name: veraltet
          in: query
          schema:
            type: string
            deprecated: true
            description: deprecated
        - name: inuse
          in: query
          schema:
            type: string
            deprecated: true
            description: deprecated
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeprecatedExample'
      responses:
        "200":
          description: Erfolgreicher Zugriff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeprecatedExample'
        "201":
          description: Erfolgreicher Zugriff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeprecatedExample'

components:
  schemas:
    DeprecatedExample:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              roomId:
                type: string
              capacity:
                type: integer
                deprecated: true
                description: Deprecated, da künftig Attribute Fassungsvermögen verwenden.

I would expect to receive two warnings, but spectral returns only one and for some reason I don't understand the last path segment was removed

OpenAPI 3.x detected
[
        {
                "code": "deprecated-header",
                "path": [
                        "paths",
                        "/all-deprecated-only-one-msg",
                        "put"
                ],
                "message": "Missing Warning header on paths./all-deprecated-only-one-msg.put.200.",
                "severity": 1,
                "range": {
                        "start": {
                                "line": 18,
                                "character": 8
                        },
                        "end": {
                                "line": 54,
                                "character": 62
                        }
                },
                "source": "...openapi.yml"
        }
]

@radicarl
Copy link
Author

radicarl commented Sep 3, 2020

still exists in 5.5.0

@radicarl
Copy link
Author

radicarl commented Sep 4, 2020

My mistake:
forgot the responses-Element in the path

@radicarl radicarl closed this as completed Sep 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
t/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant