OpenAPI link defines both operationId and operationRef

Identify a link target with either operationId or operationRef.

Description

An OpenAPI 3.0 Link Object cannot specify both operationId and operationRef. These fields are mutually exclusive even when they point to the same operation.

Potential impact

  • Specification validation may fail, or tools may handle the link inconsistently.
  • API users may be unsure which operation the link identifies.

Remediation

Use operationId for a unique operation ID in the document, or operationRef for a URI pointing to an operation. Remove the other field, then validate the target and the parameters passed to it.

Examples

The first example identifies the same operation through both operationId and operationRef. References connecting this reusable response to an operation and the external schema documents are omitted.

Before

json
{
  "openapi": "3.0.0",
  "info": {
    "title": "Simple API overview",
    "version": "1.0.0"
  },
  "paths": {
    "/": {
      "get": {
        "responses": {
          "200": {
            "description": "the user being returned",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/users/{userid}/address": {
      "parameters": [
        {
          "name": "userid",
          "in": "path",
          "required": true,
          "description": "the user identifier, as userId",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getUserAddress",
        "responses": {
          "200": {
            "description": "the user's address"
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "200": {
        "description": "the user being returned",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            }
          }
        },
        "links": {
          "address": {
            "operationId": "getUserAddress",
            "operationRef": "#/paths/~1users~1{userid}~1address/get",
            "parameters": {
              "userid": "$response.body#/uuid"
            }
          }
        }
      }
    },
    "schemas": {
      "Pet": {
        "$ref": "../models/pet.yaml"
      },
      "User": {
        "$ref": "https://api.example.com/v2/openapi.yaml#/components/schemas/User"
      }
    }
  }
}

After

json
{
  "openapi": "3.0.0",
  "info": {
    "title": "Simple API overview",
    "version": "1.0.0"
  },
  "paths": {
    "/": {
      "get": {
        "responses": {
          "200": {
            "description": "the user being returned",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/users/{userid}/address": {
      "parameters": [
        {
          "name": "userid",
          "in": "path",
          "required": true,
          "description": "the user identifier, as userId",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getUserAddress",
        "responses": {
          "200": {
            "description": "the user's address"
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "200": {
        "description": "the user being returned",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            }
          }
        },
        "links": {
          "address": {
            "operationId": "getUserAddress",
            "parameters": {
              "userid": "$response.body#/uuid"
            }
          }
        }
      }
    },
    "schemas": {
      "Pet": {
        "$ref": "../models/pet.yaml"
      },
      "User": {
        "$ref": "https://api.example.com/v2/openapi.yaml#/components/schemas/User"
      }
    }
  }
}

The second example keeps only operationId. It retains the mapping from the response’s uuid to the target userid parameter; the declaration does not automatically perform the subsequent call.

References