Describe the bug
Almost the same as issue #128, but more specifically when the unreferenced types appear as anyOf in their parents.
The fix seems easy. I saw that PR #132 (which addressed issue #128) just needed to add some search paths. So I took the same approach, duplicating the relevant search paths and changing them to anyOf, and that fixed it for me.
JToken schemaToken = openApi[OpenApiProperties.Components][OpenApiProperties.Schemas];
if (schemaToken != null)
{
RemoveItems<JProperty>(schemaToken,
paths,
i => $"$..[?(@*.$ref == '#/{OpenApiProperties.Components}/{OpenApiProperties.Schemas}/{i.Name}')]",
i => $"$..[?(@*.*.items.$ref == '#/{OpenApiProperties.Components}/{OpenApiProperties.Schemas}/{i.Name}')]",
i => $"$..[?(@*.*.allOf[?(@.$ref == '#/{OpenApiProperties.Components}/{OpenApiProperties.Schemas}/{i.Name}')])]",
i => $"$..[?(@*.*.anyOf[?(@.$ref == '#/{OpenApiProperties.Components}/{OpenApiProperties.Schemas}/{i.Name}')])]",
i => $"$..[?(@*.*.oneOf[?(@.$ref == '#/{OpenApiProperties.Components}/{OpenApiProperties.Schemas}/{i.Name}')])]",
i => $"$..allOf[?(@.$ref == '#/{OpenApiProperties.Components}/{OpenApiProperties.Schemas}/{i.Name}')]",
i => $"$..anyOf[?(@.$ref == '#/{OpenApiProperties.Components}/{OpenApiProperties.Schemas}/{i.Name}')]",
i => $"$..oneOf[?(@.$ref == '#/{OpenApiProperties.Components}/{OpenApiProperties.Schemas}/{i.Name}')]");
}
Expected behavioranyOf references should also be included in the transformed json file.
To Reproduce
SUMMARIZED downstream swagger.json. The full version is included down below.
In this example, what happens is that:
Models UpdateMarketplace and MarketplaceUpdateAction are correctly included
Models MarketplaceUpdateAction_AddCountries, MarketplaceUpdateAction_AddCurrencies and MarketplaceUpdateAction_AddLanguages are incorrectly removed
{
"paths": {
"/api/v{version}/marketplaces/{id}": {
"patch": {
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateMarketplace"
}
}
}
}
}
}
},
"components": {
"schemas": {
"UpdateMarketplace": {
"type": "object",
"properties": {
"version": {
"type": "string",
"format": "date-time"
},
"actions": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MarketplaceUpdateAction"
},
"nullable": true
}
},
"additionalProperties": false,
"description": "Updates a Marketplace."
},
"MarketplaceUpdateAction": {
"type": "object",
"anyOf": [
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_AddCountries"
},
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_AddCurrencies"
},
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_AddLanguages"
}
],
"additionalProperties": false
},
"MarketplaceUpdateAction_AddCountries": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "AddCountries"
},
"name": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of Countries to add.",
"nullable": true
}
},
"additionalProperties": false,
"description": "Adds one or more Countries to the list of supported Countries for the Marketplace."
},
"MarketplaceUpdateAction_AddCurrencies": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "AddCurrencies"
},
"name": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of Currencies to add.",
"nullable": true
}
},
"additionalProperties": false,
"description": "Adds one or more Currencies to the list of supported Currencies for the Marketplace."
},
"MarketplaceUpdateAction_AddLanguages": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "AddLanguages"
},
"name": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of Languages to add.",
"nullable": true
}
},
"additionalProperties": false,
"description": "Adds one or more Languages to the list of supported Languages for the Marketplace."
}
}
}
}
FULL original downstream swagger.json:
{
"openapi": "3.0.1",
"info": {
"title": "API v1",
"version": "v1"
},
"paths": {
"/api/v{version}/marketplaces/{id}": {
"get": {
"tags": [
"Marketplaces"
],
"summary": "Returns a Marketplace.",
"operationId": "GetMarketplace",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
},
{
"name": "version",
"in": "path",
"required": true,
"schema": {
"type": "string",
"example": "1"
},
"example": "1"
}
],
"responses": {
"200": {
"description": "OK. The Marketplace can be found in the response body.",
"content": {
"text/plain": {
"schema": {
"$ref": "#/components/schemas/Marketplace"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Marketplace"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/Marketplace"
}
}
}
},
"400": {
"description": "Bad Request. The request parameters are invalid. Inspect the response body to learn more."
},
"401": {
"description": "Unauthorized. The request was not authenticated. Ensure that you are sending the appropriate authentication token in the `Authorization` request header."
},
"403": {
"description": "Forbidden. The supplied credentials do not have the required privileges to perform the operation. Ensure that your token has at least one of the following scopes: $allowedScopesCsv."
},
"404": {
"description": "Not Found. The model could not be found."
}
}
},
"patch": {
"tags": [
"Marketplaces"
],
"summary": "Updates a Marketplace.",
"operationId": "UpdateMarketplace",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
},
{
"name": "version",
"in": "path",
"required": true,
"schema": {
"type": "string",
"example": "1"
},
"example": "1"
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateMarketplace"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/UpdateMarketplace"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/UpdateMarketplace"
}
}
}
},
"responses": {
"200": {
"description": "OK. This status will be returned for successful requests specifying the `returnModel=true`. A copy of the updated resource can be found in the response body.",
"content": {
"text/plain": {
"schema": {
"$ref": "#/components/schemas/Marketplace"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Marketplace"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/Marketplace"
}
}
}
},
"204": {
"description": "No Content. This status will be returned for successful requests not specifying the `returnModel` parameters, or specifying `returnModel=false`."
},
"400": {
"description": "Bad Request. The request body is invalid. The request parameters are invalid. Inspect the response body to learn more."
},
"401": {
"description": "Unauthorized. The request was not authenticated. Ensure that you are sending the appropriate authentication token in the `Authorization` request header."
},
"403": {
"description": "Forbidden. The supplied credentials do not have the required privileges to perform the operation. Ensure that your token has at least one of the following scopes: $allowedScopesCsv."
},
"404": {
"description": "Not Found. The model could not be found."
}
}
},
"delete": {
"tags": [
"Marketplaces"
],
"summary": "Removes a Marketplace. Only Marketplaces without any operational data may be removed. Attempting to remove a Marketplace with operational data will result in a 403 - BadRequest status code.",
"operationId": "DeleteMarketplace",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
},
{
"name": "version",
"in": "path",
"required": true,
"schema": {
"type": "string",
"example": "1"
},
"example": "1"
}
],
"responses": {
"200": {
"description": "OK. The resource was successfully removed."
},
"400": {
"description": "Bad Request. The request parameters are invalid. The request parameters are invalid. Inspect the response body to learn more."
},
"401": {
"description": "Unauthorized. The request was not authenticated. Ensure that you are sending the appropriate authentication token in the `Authorization` request header."
},
"403": {
"description": "Forbidden. The supplied credentials do not have the required privileges to perform the operation. Ensure that your token has at least one of the following scopes: $allowedScopesCsv."
},
"404": {
"description": "Not Found. The model could not be found."
}
}
}
},
"/api/v{version}/marketplaces": {
"get": {
"tags": [
"Marketplaces"
],
"summary": "Returns a list of Marketplace items.",
"operationId": "ListMarketplaces",
"parameters": [
{
"name": "Where",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "Sort",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "Expand",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "Limit",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "Offset",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "version",
"in": "path",
"required": true,
"schema": {
"type": "string",
"example": "1"
},
"example": "1"
}
],
"responses": {
"200": {
"description": "OK. A list of The Marketplace items can be found in the response body.",
"content": {
"text/plain": {
"schema": {
"$ref": "#/components/schemas/ListMarketplacesResponse"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/ListMarketplacesResponse"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/ListMarketplacesResponse"
}
}
}
},
"400": {
"description": "Bad Request. The request parameters are invalid. Inspect the response body to learn more."
},
"401": {
"description": "Unauthorized. The request was not authenticated. Ensure that you are sending the appropriate authentication token in the `Authorization` request header."
},
"403": {
"description": "Forbidden. The supplied credentials do not have the required privileges to perform the operation. Ensure that your token has at least one of the following scopes: $allowedScopesCsv."
}
}
},
"post": {
"tags": [
"Marketplaces"
],
"summary": "Adds a new Marketplace.",
"operationId": "CreateMarketplace",
"parameters": [
{
"name": "version",
"in": "path",
"required": true,
"schema": {
"type": "string",
"example": "1"
},
"example": "1"
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateMarketplace"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/CreateMarketplace"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/CreateMarketplace"
}
}
}
},
"responses": {
"201": {
"description": "Created. If the request specified `returnModel=true`, a copy of the created resource can be found in the response body. The resource URL can be found in the `Location` header of the response.",
"content": {
"text/plain": {
"schema": {
"$ref": "#/components/schemas/Marketplace"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Marketplace"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/Marketplace"
}
}
}
},
"400": {
"description": "Bad Request. The request body is invalid. The request parameters are invalid. Inspect the response body to learn more."
},
"401": {
"description": "Unauthorized. The request was not authenticated. Ensure that you are sending the appropriate authentication token in the `Authorization` request header."
},
"403": {
"description": "Forbidden. The supplied credentials do not have the required privileges to perform the operation. Ensure that your token has at least one of the following scopes: $allowedScopesCsv."
}
}
}
}
},
"components": {
"schemas": {
"AuditInfo": {
"type": "object",
"properties": {
"userId": {
"type": "string",
"description": "Unique identifier of the user who created or modified a resource",
"format": "uuid"
},
"role": {
"type": "string",
"description": "Role of the user who created or modified a resource.",
"nullable": true
},
"dateTime": {
"type": "string",
"description": "Date and time when the creation or modification took place.",
"format": "date-time"
}
},
"additionalProperties": false,
"description": "Information about who performed an action, and when."
},
"AuditInfoCreatedModified": {
"type": "object",
"properties": {
"created": {
"$ref": "#/components/schemas/AuditInfo"
},
"lastModified": {
"$ref": "#/components/schemas/AuditInfo"
}
},
"additionalProperties": false,
"description": "Information about who performed an action, and when."
},
"CreateMarketplace": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Name of the Marketplace.",
"nullable": true
},
"countries": {
"type": "array",
"items": {
"type": "string"
},
"description": "The list of Countries where the Marketplace is configured to operate. Users will be able to browse the Marketplace from other Countries, but some restrictions may apply, such as completing purchases.",
"nullable": true
},
"currencies": {
"type": "array",
"items": {
"type": "string"
},
"description": "The list of Currencies enabled for the Markeplace. This will limit the Currencies that prices and discounts can be registered in, as well as which Currencies will be accepted in payments.",
"nullable": true
},
"languages": {
"type": "array",
"items": {
"type": "string"
},
"description": "The list of Languages enabled for the Marketplace. This will limit the Languages that content can be registered in, such as Catalog information, Meta Tags and others.",
"nullable": true
}
},
"additionalProperties": false,
"description": "Adds a new Marketplace."
},
"ListMarketplacesResponse": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Marketplace"
},
"nullable": true
},
"totalCount": {
"type": "integer",
"format": "int32"
}
},
"additionalProperties": false
},
"Marketplace": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier of the Marketplace.",
"format": "uuid"
},
"version": {
"type": "integer",
"description": "Current version of the Marketplace.",
"format": "int64"
},
"name": {
"type": "string",
"description": "Name of the Marketplace.",
"nullable": true
},
"isActive": {
"type": "boolean",
"description": "Whether this Marketplace is enabled for operation."
},
"countries": {
"type": "array",
"items": {
"type": "string"
},
"description": "The list of Countries where the Marketplace is configured to operate. Users will be able to browse the Marketplace from other Countries, but some restrictions may apply, such as completing purchases.",
"nullable": true
},
"currencies": {
"type": "array",
"items": {
"type": "string"
},
"description": "The list of Currencies enabled for the Markeplace. This will limit the Currencies that prices and discounts can be registered in, as well as which Currencies will be accepted in payments.",
"nullable": true
},
"languages": {
"type": "array",
"items": {
"type": "string"
},
"description": "The list of Languages enabled for the Marketplace. This will limit the Languages that content can be registered in, such as Catalog information, Meta Tags and others.",
"nullable": true
},
"metaTag": {
"$ref": "#/components/schemas/MetaTag"
},
"reviewsConfiguration": {
"$ref": "#/components/schemas/ReviewsConfiguration"
},
"auditInfo": {
"$ref": "#/components/schemas/AuditInfoCreatedModified"
}
},
"additionalProperties": false,
"description": "Holds information about Marketplaces registered in the INA Marketplace Platform. It is also the endpoint to register and configure new Marketplaces, as well as update configuration for running Marketplaces."
},
"MarketplaceUpdateAction": {
"type": "object",
"anyOf": [
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_AddCountries"
},
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_AddCurrencies"
},
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_AddLanguages"
},
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_RemoveCountries"
},
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_RemoveCurrencies"
},
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_RemoveLanguages"
},
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_SetIsActive"
},
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_SetMetaTag"
},
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_SetName"
},
{
"$ref": "#/components/schemas/MarketplaceUpdateAction_SetReviewsConfiguration"
}
],
"additionalProperties": false
},
"MarketplaceUpdateAction_AddCountries": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "AddCountries"
},
"name": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of Countries to add.",
"nullable": true
}
},
"additionalProperties": false,
"description": "Adds one or more Countries to the list of supported Countries for the Marketplace."
},
"MarketplaceUpdateAction_AddCurrencies": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "AddCurrencies"
},
"name": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of Currencies to add.",
"nullable": true
}
},
"additionalProperties": false,
"description": "Adds one or more Currencies to the list of supported Currencies for the Marketplace."
},
"MarketplaceUpdateAction_AddLanguages": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "AddLanguages"
},
"name": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of Languages to add.",
"nullable": true
}
},
"additionalProperties": false,
"description": "Adds one or more Languages to the list of supported Languages for the Marketplace."
},
"MarketplaceUpdateAction_RemoveCountries": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "RemoveCountries"
},
"name": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of Countries to remove.",
"nullable": true
}
},
"additionalProperties": false,
"description": "Removes one or more Countries from the list of supported Countries for the Marketplace."
},
"MarketplaceUpdateAction_RemoveCurrencies": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "RemoveCurrencies"
},
"name": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of Currencies to remove.",
"nullable": true
}
},
"additionalProperties": false,
"description": "Removes one or more Currencies to the list of supported Currencies for the Marketplace."
},
"MarketplaceUpdateAction_RemoveLanguages": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "RemoveLanguages"
},
"name": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of Languages to remove.",
"nullable": true
}
},
"additionalProperties": false,
"description": "Removes one or more Languages from the list of supported Languages for the Marketplace."
},
"MarketplaceUpdateAction_SetIsActive": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "SetIsActive"
},
"isActive": {
"type": "boolean",
"description": "`true` to set as active, `false` to set as NOT active."
}
},
"additionalProperties": false,
"description": "Sets whether the Marketplace is active."
},
"MarketplaceUpdateAction_SetMetaTag": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "SetMetaTag"
},
"name": {
"$ref": "#/components/schemas/MetaTag"
}
},
"additionalProperties": false,
"description": "Sets the Meta Tag of the Marketplace."
},
"MarketplaceUpdateAction_SetName": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "SetName"
},
"name": {
"type": "string",
"description": "Name of the Marketplace.",
"nullable": true
}
},
"additionalProperties": false,
"description": "Sets the name of the Marketplace."
},
"MarketplaceUpdateAction_SetReviewsConfiguration": {
"type": "object",
"properties": {
"actionName": {
"type": "string",
"example": "SetReviewsConfiguration"
},
"reviewsConfiguration": {
"$ref": "#/components/schemas/ReviewsConfigurationDraft"
}
},
"additionalProperties": false,
"description": "Sets the `reviewsConfiguration` field."
},
"MetaTag": {
"type": "object",
"properties": {
"title": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Localized title of the meta tag.",
"nullable": true
},
"description": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Localized description of the meta tag.",
"nullable": true
},
"keywords": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Localized keywords of the meta tag.",
"nullable": true
}
},
"additionalProperties": false,
"description": "Meta tag to support SEO."
},
"ReviewsConfiguration": {
"type": "object",
"properties": {
"enableReviews": {
"type": "boolean",
"description": "Whether this Marketplace enables reviews."
},
"enableAnonymousReviews": {
"type": "boolean",
"description": "Whether authors can write reviews without logging in."
}
},
"additionalProperties": false,
"description": "Determines how Reviews work in the Marketplace."
},
"ReviewsConfigurationDraft": {
"type": "object",
"properties": {
"enableReviews": {
"type": "boolean",
"description": "Whether this Marketplace enables reviews."
},
"enableAnonymousReviews": {
"type": "boolean",
"description": "Whether authors can write reviews without logging in."
}
},
"additionalProperties": false,
"description": "Determines how Reviews work in the Marketplace."
},
"UpdateMarketplace": {
"type": "object",
"properties": {
"version": {
"type": "string",
"format": "date-time"
},
"actions": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MarketplaceUpdateAction"
},
"nullable": true
}
},
"additionalProperties": false,
"description": "Updates a Marketplace."
}
}
}
}
Describe the bug Almost the same as issue #128, but more specifically when the unreferenced types appear as
anyOf
in their parents.The fix seems easy. I saw that PR #132 (which addressed issue #128) just needed to add some search paths. So I took the same approach, duplicating the relevant search paths and changing them to
anyOf
, and that fixed it for me.File: SwaggerJsonTransformer.cs Method: TransformOpenApi
Expected behavior
anyOf
references should also be included in the transformed json file.To Reproduce
SUMMARIZED downstream swagger.json. The full version is included down below.
In this example, what happens is that:
UpdateMarketplace
andMarketplaceUpdateAction
are correctly includedMarketplaceUpdateAction_AddCountries
,MarketplaceUpdateAction_AddCurrencies
andMarketplaceUpdateAction_AddLanguages
are incorrectly removedFULL original downstream swagger.json: