{
"openapi": "3.0.1",
"info": {
"title": "JsonApiDotNetCoreExample",
"version": "1.0"
},
"servers": [
{
"url": "https://localhost:44340"
}
],
"paths": {
"/api/todoItems": {
"get": {
"tags": [
"todoItems"
],
"summary": "Retrieves a collection of todoItems.",
"operationId": "getTodoItemCollection",
"parameters": [
{
"name": "query",
"in": "query",
"description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string",
"nullable": true
},
"example": ""
}
}
],
"responses": {
"200": {
"description": "Successfully returns the found todoItems, or an empty array if none were found.",
"content": {
"application/vnd.api+json": {
"schema": {
"$ref": "#/components/schemas/todoItemCollectionResponseDocument"
}
}
}
},
"400": {
"description": "The query string is invalid."
}
}
}
},
"/api/todoItems/{id}": {
"get": {
"tags": [
"todoItems"
],
"summary": "Retrieves an individual todoItem by its identifier.",
"operationId": "getTodoItem",
"parameters": [
{
"name": "id",
"in": "path",
"description": "The identifier of the todoItem to retrieve.",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "query",
"in": "query",
"description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string",
"nullable": true
},
"example": ""
}
}
],
"responses": {
"200": {
"description": "Successfully returns the found todoItem.",
"content": {
"application/vnd.api+json": {
"schema": {
"$ref": "#/components/schemas/todoItemPrimaryResponseDocument"
}
}
}
},
"400": {
"description": "The query string is invalid."
},
"404": {
"description": "The todoItem does not exist."
}
}
}
}
},
"components": {
"schemas": {
"dataInResponse": {
"required": [
"id",
"type"
],
"type": "object",
"properties": {
"type": {
"minLength": 1,
"type": "string"
},
"id": {
"minLength": 1,
"type": "string"
}
},
"additionalProperties": false,
"discriminator": {
"propertyName": "type",
"mapping": {
"tags": "#/components/schemas/tagDataInResponse",
"todoItems": "#/components/schemas/todoItemDataInResponse"
}
},
"x-abstract": true
},
"tagAttributesInResponse": {
"type": "object",
"properties": {
"name": {
"minLength": 1,
"type": "string"
}
},
"additionalProperties": false
},
"tagDataInResponse": {
"allOf": [
{
"$ref": "#/components/schemas/dataInResponse"
},
{
"type": "object",
"properties": {
"attributes": {
"allOf": [
{
"$ref": "#/components/schemas/tagAttributesInResponse"
}
]
},
"relationships": {
"allOf": [
{
"$ref": "#/components/schemas/tagRelationshipsInResponse"
}
]
}
},
"additionalProperties": false
}
],
"additionalProperties": false
},
"tagIdentifier": {
"required": [
"id",
"type"
],
"type": "object",
"properties": {
"type": {
"$ref": "#/components/schemas/tagResourceType"
},
"id": {
"minLength": 1,
"type": "string"
}
},
"additionalProperties": false
},
"tagRelationshipsInResponse": {
"type": "object",
"properties": {
"todoItems": {
"allOf": [
{
"$ref": "#/components/schemas/toManyTodoItemInResponse"
}
]
}
},
"additionalProperties": false
},
"tagResourceType": {
"enum": [
"tags"
],
"type": "string",
"additionalProperties": false
},
"toManyTagInResponse": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/tagIdentifier"
}
}
},
"additionalProperties": false
},
"toManyTodoItemInResponse": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/todoItemIdentifier"
}
}
},
"additionalProperties": false
},
"todoItemAttributesInResponse": {
"type": "object",
"properties": {
"description": {
"type": "string"
}
},
"additionalProperties": false
},
"todoItemCollectionResponseDocument": {
"required": [
"data"
],
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/todoItemDataInResponse"
}
},
"included": {
"type": "array",
"items": {
"$ref": "#/components/schemas/dataInResponse"
}
}
},
"additionalProperties": false
},
"todoItemDataInResponse": {
"allOf": [
{
"$ref": "#/components/schemas/dataInResponse"
},
{
"type": "object",
"properties": {
"attributes": {
"allOf": [
{
"$ref": "#/components/schemas/todoItemAttributesInResponse"
}
]
},
"relationships": {
"allOf": [
{
"$ref": "#/components/schemas/todoItemRelationshipsInResponse"
}
]
}
},
"additionalProperties": false
}
],
"additionalProperties": false
},
"todoItemIdentifier": {
"required": [
"id",
"type"
],
"type": "object",
"properties": {
"type": {
"$ref": "#/components/schemas/todoItemResourceType"
},
"id": {
"minLength": 1,
"type": "string"
}
},
"additionalProperties": false
},
"todoItemPrimaryResponseDocument": {
"required": [
"data"
],
"type": "object",
"properties": {
"data": {
"allOf": [
{
"$ref": "#/components/schemas/todoItemDataInResponse"
}
]
},
"included": {
"type": "array",
"items": {
"$ref": "#/components/schemas/dataInResponse"
}
}
},
"additionalProperties": false
},
"todoItemRelationshipsInResponse": {
"type": "object",
"properties": {
"tags": {
"allOf": [
{
"$ref": "#/components/schemas/toManyTagInResponse"
}
]
}
},
"additionalProperties": false
},
"todoItemResourceType": {
"enum": [
"todoItems"
],
"type": "string",
"additionalProperties": false
}
}
}
}
When using inheritance using
allOf, Kiota generates multiple identical classes for the same component schema. As a result, the types are incompatible when trying to consume the C# code generated by Kiota.I've tried to create a minimal repro, but the OAS is still quite large. The full file is provided below. At a high level, the structure contains the following base component schema:
with derived schemas
tagDataInResponseandtodoItemDataInResponse, ie:These schemas are used from two GET endpoints, one returning a collection and the other a singular item. The response schema in both cases contains a
dataproperty (derived schema reference, or an array of that) and anincludedproperty (array of base schema reference).The first endpoint (
paths./api/todoItems.get) uses the following response schema:And the second endpoint (
paths./api/todoItems/{id}.get) uses the following schema:I would have expected Kiota to generate the base class
DataInResponse, with the two derived classesTodoItemDataInResponseandTagDataInResponse. What happens is that Kiota also generates the derived classTodoItems, whose content is identical toTodoItemDataInResponse. The unexpectedTodoItemsclass is only used by the singular endpoint.As a result, it's not possible to define a method that takes a parameter of type
TodoItemDataInResponseand is called with the response from both endpoints. I would have expected to be able to write:Instead, the code for method
PrintTodoItemneeds to be duplicated, because the types are incompatible:Additionally, because there are duplicate types, it's unclear for consumers of the API what to upcast/type-check for when looping over the entries in
included.When using NSwag to generate the client, types appear as expected, which makes me believe the OAS is correct.
Expand to view the full OAS file
{ "openapi": "3.0.1", "info": { "title": "JsonApiDotNetCoreExample", "version": "1.0" }, "servers": [ { "url": "https://localhost:44340" } ], "paths": { "/api/todoItems": { "get": { "tags": [ "todoItems" ], "summary": "Retrieves a collection of todoItems.", "operationId": "getTodoItemCollection", "parameters": [ { "name": "query", "in": "query", "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", "schema": { "type": "object", "additionalProperties": { "type": "string", "nullable": true }, "example": "" } } ], "responses": { "200": { "description": "Successfully returns the found todoItems, or an empty array if none were found.", "content": { "application/vnd.api+json": { "schema": { "$ref": "#/components/schemas/todoItemCollectionResponseDocument" } } } }, "400": { "description": "The query string is invalid." } } } }, "/api/todoItems/{id}": { "get": { "tags": [ "todoItems" ], "summary": "Retrieves an individual todoItem by its identifier.", "operationId": "getTodoItem", "parameters": [ { "name": "id", "in": "path", "description": "The identifier of the todoItem to retrieve.", "required": true, "schema": { "type": "string" } }, { "name": "query", "in": "query", "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", "schema": { "type": "object", "additionalProperties": { "type": "string", "nullable": true }, "example": "" } } ], "responses": { "200": { "description": "Successfully returns the found todoItem.", "content": { "application/vnd.api+json": { "schema": { "$ref": "#/components/schemas/todoItemPrimaryResponseDocument" } } } }, "400": { "description": "The query string is invalid." }, "404": { "description": "The todoItem does not exist." } } } } }, "components": { "schemas": { "dataInResponse": { "required": [ "id", "type" ], "type": "object", "properties": { "type": { "minLength": 1, "type": "string" }, "id": { "minLength": 1, "type": "string" } }, "additionalProperties": false, "discriminator": { "propertyName": "type", "mapping": { "tags": "#/components/schemas/tagDataInResponse", "todoItems": "#/components/schemas/todoItemDataInResponse" } }, "x-abstract": true }, "tagAttributesInResponse": { "type": "object", "properties": { "name": { "minLength": 1, "type": "string" } }, "additionalProperties": false }, "tagDataInResponse": { "allOf": [ { "$ref": "#/components/schemas/dataInResponse" }, { "type": "object", "properties": { "attributes": { "allOf": [ { "$ref": "#/components/schemas/tagAttributesInResponse" } ] }, "relationships": { "allOf": [ { "$ref": "#/components/schemas/tagRelationshipsInResponse" } ] } }, "additionalProperties": false } ], "additionalProperties": false }, "tagIdentifier": { "required": [ "id", "type" ], "type": "object", "properties": { "type": { "$ref": "#/components/schemas/tagResourceType" }, "id": { "minLength": 1, "type": "string" } }, "additionalProperties": false }, "tagRelationshipsInResponse": { "type": "object", "properties": { "todoItems": { "allOf": [ { "$ref": "#/components/schemas/toManyTodoItemInResponse" } ] } }, "additionalProperties": false }, "tagResourceType": { "enum": [ "tags" ], "type": "string", "additionalProperties": false }, "toManyTagInResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/tagIdentifier" } } }, "additionalProperties": false }, "toManyTodoItemInResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/todoItemIdentifier" } } }, "additionalProperties": false }, "todoItemAttributesInResponse": { "type": "object", "properties": { "description": { "type": "string" } }, "additionalProperties": false }, "todoItemCollectionResponseDocument": { "required": [ "data" ], "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/todoItemDataInResponse" } }, "included": { "type": "array", "items": { "$ref": "#/components/schemas/dataInResponse" } } }, "additionalProperties": false }, "todoItemDataInResponse": { "allOf": [ { "$ref": "#/components/schemas/dataInResponse" }, { "type": "object", "properties": { "attributes": { "allOf": [ { "$ref": "#/components/schemas/todoItemAttributesInResponse" } ] }, "relationships": { "allOf": [ { "$ref": "#/components/schemas/todoItemRelationshipsInResponse" } ] } }, "additionalProperties": false } ], "additionalProperties": false }, "todoItemIdentifier": { "required": [ "id", "type" ], "type": "object", "properties": { "type": { "$ref": "#/components/schemas/todoItemResourceType" }, "id": { "minLength": 1, "type": "string" } }, "additionalProperties": false }, "todoItemPrimaryResponseDocument": { "required": [ "data" ], "type": "object", "properties": { "data": { "allOf": [ { "$ref": "#/components/schemas/todoItemDataInResponse" } ] }, "included": { "type": "array", "items": { "$ref": "#/components/schemas/dataInResponse" } } }, "additionalProperties": false }, "todoItemRelationshipsInResponse": { "type": "object", "properties": { "tags": { "allOf": [ { "$ref": "#/components/schemas/toManyTagInResponse" } ] } }, "additionalProperties": false }, "todoItemResourceType": { "enum": [ "todoItems" ], "type": "string", "additionalProperties": false } } } }I'm using the next command to generate the client code:
Used versions: