Skip to content

OpenAPI schema references feedback #56318

Closed
@martincostello

Description

@martincostello

Hot off the presses, the app I'm testing daily builds and OpenAPI with has picked up the changes from #56175 and there's a few things in the new schema that seem a bit odd to me. Some might be intentional, some might be known and just not gotten to yet, so sorry if any of this is just noise.

The observations are also based on comparison to NSwag's and Swashbuckle.AspNetCore's current behaviour, though I appreciate one-to-one parity isn't a goal.

The points referenced below are all from commit martincostello/api@f72f01b using Microsoft.AspNetCore.OpenApi 9.0.0-preview.6.24318.18. The schema generated is at the bottom of this issue.

Overly inlined schemas?

One of the components in the schema is this:

"string": {
  "type": "string"
}

This seems maybe a bit too normalized compared to the relevant properties in an associated model just being declared as of type string directly?

Question marks in schema names

One of the schema names is generated thus:

"int?": {
  "type": "integer",
  "format": "int32",
  "nullable": true
}

I wonder if some client generation tooling might have issues with trying to generate models with a ? in the name? It's at least not something I've seen before.

Inconsistent schema names for nullable types?

In the generated OpenAPI document is the following schema:

"string2": {
  "type": "string",
  "nullable": true
}

This seems to be inconsistent with the int? schema - assuming the question marks as intentional in the names. I would have thought string? would be the more appropriate name for the sake of comparison with another nullable type.

Inline objects still rendered for operations

The following schema is present inline for the response of one of the operations:

"schema": {
  "type": "object",
  "properties": {
    "decryptionKey": {
      "$ref": "#/components/schemas/string"
    },
    "validationKey": {
      "$ref": "#/components/schemas/string"
    },
    "machineKeyXml": {
      "$ref": "#/components/schemas/string"
    }
  }
}

I would have expected the response to be a reference to a schema for the type as a whole, and then the model emitted as a component which is itself composed of three string properties (notwithstanding the point above about maybe too much inlining).

/cc @captainsafia

OpenAPI schema
{
  "openapi": "3.0.1",
  "info": {
    "title": "api.martincostello.com",
    "description": "Martin Costello's API",
    "contact": {
      "name": "Martin Costello",
      "url": "https://martincostello.com/"
    },
    "license": {
      "name": "This API is licensed under the MIT License.",
      "url": "https://github.com/martincostello/api/blob/main/LICENSE"
    },
    "version": ""
  },
  "paths": {
    "/time": {
      "get": {
        "tags": [
          "API"
        ],
        "summary": "Gets the current UTC time.",
        "description": "Gets the current date and time in UTC.",
        "operationId": "Time",
        "responses": {
          "200": {
            "description": "The current UTC date and time.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "rfc1123": {
                      "$ref": "#/components/schemas/string"
                    },
                    "unix": {
                      "type": "integer",
                      "format": "int64"
                    },
                    "universalSortable": {
                      "$ref": "#/components/schemas/string"
                    },
                    "universalFull": {
                      "$ref": "#/components/schemas/string"
                    }
                  }
                },
                "example": {
                  "timestamp": "2016-06-03T18:44:14+00:00",
                  "rfc1123": "Fri, 03 Jun 2016 18:44:14 GMT",
                  "unix": 1464979454,
                  "universalSortable": "2016-06-03 18:44:14Z",
                  "universalFull": "Friday, 03 June 2016 18:44:14"
                }
              }
            }
          }
        }
      }
    },
    "/tools/guid": {
      "get": {
        "tags": [
          "API"
        ],
        "summary": "Generates a GUID.",
        "description": "Generates a new GUID in the specified format.",
        "operationId": "Guid",
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "The format for which to generate a GUID.",
              "nullable": true
            },
            "example": "D"
          },
          {
            "name": "uppercase",
            "in": "query",
            "schema": {
              "type": "boolean",
              "description": "Whether to return the GUID in uppercase.",
              "nullable": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A GUID was generated successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "guid": {
                      "$ref": "#/components/schemas/string"
                    }
                  }
                },
                "example": {
                  "guid": "6bc55a07-3d3e-4d52-8701-362a1187772d"
                }
              }
            }
          },
          "400": {
            "description": "The specified format is invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
                  "title": "Bad Request",
                  "status": 400,
                  "detail": "The specified value is invalid."
                }
              }
            }
          }
        }
      }
    },
    "/tools/hash": {
      "post": {
        "tags": [
          "API"
        ],
        "summary": "Hashes a string.",
        "description": "Generates a hash of some plaintext for a specified hash algorithm and returns it in the required format.",
        "operationId": "Hash",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "algorithm",
                  "format",
                  "plaintext"
                ],
                "type": "object",
                "properties": {
                  "algorithm": {
                    "$ref": "#/components/schemas/string"
                  },
                  "format": {
                    "$ref": "#/components/schemas/string"
                  },
                  "plaintext": {
                    "$ref": "#/components/schemas/string"
                  }
                },
                "nullable": true
              },
              "example": {
                "algorithm": "sha256",
                "format": "base64",
                "plaintext": "The quick brown fox jumped over the lazy dog"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The hash was generated successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "hash": {
                      "$ref": "#/components/schemas/string"
                    }
                  }
                },
                "example": {
                  "hash": "fTi1zSWiuvha07tbkxE4PmcaihQuswKzJNSl+6h0jGk="
                }
              }
            }
          },
          "400": {
            "description": "The specified hash algorithm or output format is invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
                  "title": "Bad Request",
                  "status": 400,
                  "detail": "The specified value is invalid."
                }
              }
            }
          }
        }
      }
    },
    "/tools/machinekey": {
      "get": {
        "tags": [
          "API"
        ],
        "summary": "Generates a machine key.",
        "description": "Generates a machine key for a Web.config configuration file for ASP.NET.",
        "operationId": "MachineKey",
        "parameters": [
          {
            "name": "decryptionAlgorithm",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "The name of the decryption algorithm.",
              "nullable": true
            },
            "example": "AES-256"
          },
          {
            "name": "validationAlgorithm",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "The name of the validation algorithm.",
              "nullable": true
            },
            "example": "SHA1"
          }
        ],
        "responses": {
          "200": {
            "description": "The machine key was generated successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "decryptionKey": {
                      "$ref": "#/components/schemas/string"
                    },
                    "validationKey": {
                      "$ref": "#/components/schemas/string"
                    },
                    "machineKeyXml": {
                      "$ref": "#/components/schemas/string"
                    }
                  }
                },
                "example": {
                  "decryptionKey": "2EA72C07DEEF522B4686C39BDF83E70A96BA92EE1D960029821FCA2E4CD9FB72",
                  "validationKey": "0A7A92827A74B9B4D2A21918814D8E4A9150BB5ADDB284533BDB50E44ADA6A4BCCFF637A5CB692816EE304121A1BCAA5A6D96BE31A213DEE0BAAEF102A391E8F",
                  "machineKeyXml": "<machineKey validationKey=\"0A7A92827A74B9B4D2A21918814D8E4A9150BB5ADDB284533BDB50E44ADA6A4BCCFF637A5CB692816EE304121A1BCAA5A6D96BE31A213DEE0BAAEF102A391E8F\" decryptionKey=\"2EA72C07DEEF522B4686C39BDF83E70A96BA92EE1D960029821FCA2E4CD9FB72\" validation=\"SHA1\" decryption=\"AES\" />"
                }
              }
            }
          },
          "400": {
            "description": "The specified decryption or validation algorithm is invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
                  "title": "Bad Request",
                  "status": 400,
                  "detail": "The specified value is invalid."
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "int?": {
        "type": "integer",
        "format": "int32",
        "nullable": true
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/string2"
          },
          "title": {
            "$ref": "#/components/schemas/string2"
          },
          "status": {
            "$ref": "#/components/schemas/int?"
          },
          "detail": {
            "$ref": "#/components/schemas/string2"
          },
          "instance": {
            "$ref": "#/components/schemas/string2"
          }
        }
      },
      "string": {
        "type": "string"
      },
      "string2": {
        "type": "string",
        "nullable": true
      }
    }
  },
  "tags": [
    {
      "name": "API"
    }
  ]
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions