Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Microsoft.OpenApi/Models/OpenApiOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,8 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version
writer.WriteProperty(OpenApiConstants.Deprecated, Deprecated, false);

// security
writer.WriteOptionalCollection(OpenApiConstants.Security, Security, callback);

writer.WriteOptionalOrEmptyCollection(OpenApiConstants.Security, Security, callback);
// servers
writer.WriteOptionalCollection(OpenApiConstants.Servers, Servers, callback);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using Microsoft.OpenApi.Models.References;
using Microsoft.OpenApi.Models.Interfaces;
using System;
using Microsoft.OpenApi.Interfaces;
using System.Text.Json.Nodes;

namespace Microsoft.OpenApi.Reader.V2
{
Expand Down Expand Up @@ -96,7 +96,10 @@ internal static partial class OpenApiV2Deserializer
},
{
"security",
(o, n, t) => o.Security = n.CreateList(LoadSecurityRequirement, t)
(o, n, t) => { if (n.JsonNode is JsonArray)
{
o.Security = new List<OpenApiSecurityRequirement>(n.CreateList(LoadSecurityRequirement, t));
} }
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Nodes;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Models.References;
Expand Down Expand Up @@ -83,7 +84,13 @@ internal static partial class OpenApiV3Deserializer
},
{
"security",
(o, n, t) => o.Security = n.CreateList(LoadSecurityRequirement, t)
(o, n, t) =>
{
if (n.JsonNode is JsonArray)
{
o.Security = n.CreateList(LoadSecurityRequirement, t);
}
}
},
{
"servers",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Nodes;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Models.References;
Expand Down Expand Up @@ -96,8 +97,11 @@ internal static partial class OpenApiV31Deserializer
},
{
"security", (o, n, t) =>
{
o.Security = n.CreateList(LoadSecurityRequirement, t);
{
if (n.JsonNode is JsonArray)
{
o.Security = new List<OpenApiSecurityRequirement>(n.CreateList(LoadSecurityRequirement, t));
}
}
},
{
Expand Down
20 changes: 20 additions & 0 deletions src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,26 @@ public static void WriteOptionalCollection<T>(
writer.WriteCollectionInternal(name, elements, action);
}
}

/// <summary>
/// Write the optional or empty Open API object/element collection.
/// </summary>
/// <typeparam name="T">The Open API element type. <see cref="IOpenApiElement"/></typeparam>
/// <param name="writer">The Open API writer.</param>
/// <param name="name">The property name.</param>
/// <param name="elements">The collection values.</param>
/// <param name="action">The collection element writer action.</param>
public static void WriteOptionalOrEmptyCollection<T>(
this IOpenApiWriter writer,
string name,
IEnumerable<T>? elements,
Action<IOpenApiWriter, T> action)
{
if (elements != null)
{
writer.WriteCollectionInternal(name, elements, action);
}
}

/// <summary>
/// Write the required Open API object/element collection.
Expand Down
8 changes: 8 additions & 0 deletions test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,13 @@
</None>

<None Update="PublicApi\PublicApi.approved.txt" CopyToOutputDirectory="Always" />

<None Update="Models\Samples\docWithoutOperationSecurity.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

<None Update="Models\Samples\docWithEmptyOperationSecurity.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
69 changes: 66 additions & 3 deletions test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@
using System.Threading.Tasks;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Models.Interfaces;
using Microsoft.OpenApi.Models.References;
using Microsoft.OpenApi.Writers;
using Microsoft.VisualBasic;
using VerifyXunit;
using Xunit;

Expand Down Expand Up @@ -2179,7 +2177,7 @@ public void SerializeAsThrowsIfVersionIsNotSupported()
}

[Fact]
public async Task SerializeDocWithSecuritySchemeWithInlineRefererencesWorks()
public async Task SerializeDocWithSecuritySchemeWithInlineReferencesWorks()
{
var expected = @"openapi: 3.0.4
info:
Expand Down Expand Up @@ -2220,5 +2218,70 @@ public async Task SerializeDocWithSecuritySchemeWithInlineRefererencesWorks()
var actual = stringWriter.ToString();
Assert.Equal(expected.MakeLineBreaksEnvironmentNeutral(), actual.MakeLineBreaksEnvironmentNeutral());
}

[Fact]
public async Task SerializeDocWithoutOperationSecurityWorks()
{
var expected = """
openapi: 3.0.4
info:
title: Repair Service
version: 1.0.0
servers:
- url: https://pluginrentu.azurewebsites.net/api
paths:
/repairs:
get:
summary: List all repairs
description: Returns a list of repairs with their details and images
operationId: listRepairs
responses:
'200':
description: A list of repairs
content:
application/json:
schema:
type: object
""";

var doc = (await OpenApiDocument.LoadAsync("Models/Samples/docWithoutOperationSecurity.yaml", SettingsFixture.ReaderSettings)).Document;
var stringWriter = new StringWriter();
doc!.SerializeAsV3(new OpenApiYamlWriter(stringWriter, new OpenApiWriterSettings { InlineLocalReferences = true }));
var actual = stringWriter.ToString();
Assert.Equal(expected.MakeLineBreaksEnvironmentNeutral(), actual.MakeLineBreaksEnvironmentNeutral());
}

[Fact]
public async Task SerializeDocWithEmptyOperationSecurityWorks()
{
var expected = """
openapi: 3.0.4
info:
title: Repair Service
version: 1.0.0
servers:
- url: https://pluginrentu.azurewebsites.net/api
paths:
/repairs:
get:
summary: List all repairs
description: Returns a list of repairs with their details and images
operationId: listRepairs
responses:
'200':
description: A list of repairs
content:
application/json:
schema:
type: object
security: [ ]
""";

var doc = (await OpenApiDocument.LoadAsync("Models/Samples/docWithEmptyOperationSecurity.yaml", SettingsFixture.ReaderSettings)).Document;
var stringWriter = new StringWriter();
doc!.SerializeAsV3(new OpenApiYamlWriter(stringWriter, new OpenApiWriterSettings { InlineLocalReferences = true }));
var actual = stringWriter.ToString();
Assert.Equal(expected.MakeLineBreaksEnvironmentNeutral(), actual.MakeLineBreaksEnvironmentNeutral());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
openapi: 3.0.0
info:
title: Repair Service
version: 1.0.0
servers:
- url: https://pluginrentu.azurewebsites.net/api
paths:
/repairs:
get:
operationId: listRepairs
summary: List all repairs
description: Returns a list of repairs with their details and images
responses:
'200':
description: A list of repairs
content:
application/json:
schema:
type: object
security: []
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
openapi: 3.0.0
info:
title: Repair Service
version: 1.0.0
servers:
- url: https://pluginrentu.azurewebsites.net/api
paths:
/repairs:
get:
operationId: listRepairs
summary: List all repairs
description: Returns a list of repairs with their details and images
responses:
'200':
description: A list of repairs
content:
application/json:
schema:
type: object
Original file line number Diff line number Diff line change
Expand Up @@ -1975,6 +1975,7 @@ namespace Microsoft.OpenApi.Writers
public static void WriteOptionalMap<T>(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.Dictionary<string, T>? elements, System.Action<Microsoft.OpenApi.Writers.IOpenApiWriter, string, T> action)
where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { }
public static void WriteOptionalObject<T>(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, T? value, System.Action<Microsoft.OpenApi.Writers.IOpenApiWriter, T> action) { }
public static void WriteOptionalOrEmptyCollection<T>(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IEnumerable<T>? elements, System.Action<Microsoft.OpenApi.Writers.IOpenApiWriter, T> action) { }
public static void WriteProperty(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, string? value) { }
public static void WriteProperty(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, bool value, bool defaultValue = false) { }
public static void WriteProperty(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, bool? value, bool defaultValue = false) { }
Expand Down