Skip to content

Added YAML Support to Examples #185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [7.0.3] - 2021-07-30
### Added
- Support for YAML examples
- Infrastructure to easily add more supported formats

## [7.0.2] - 2021-04-03
### Fixed
- Fixed License
Expand Down
4 changes: 2 additions & 2 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.1;net5.0</TargetFrameworks>
<PackageVersion>7.0.2</PackageVersion>
<PackageVersion>7.0.3</PackageVersion>
<Authors>Matt Frear</Authors>
<Description>Some additional useful filters for Swashbuckle.AspNetCore. This package replaces Swashbuckle.AspNetCore.Examples.</Description>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
Expand All @@ -19,7 +19,7 @@
</PropertyGroup>

<PropertyGroup>
<VersionPrefix>7.0.2</VersionPrefix>
<VersionPrefix>7.0.3</VersionPrefix>
<VersionSuffix></VersionSuffix>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>..\key.snk</AssemblyOriginatorKeyFile>
Expand Down
26 changes: 7 additions & 19 deletions src/Swashbuckle.AspNetCore.Filters/Examples/ExamplesConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Swashbuckle.AspNetCore.Filters.Examples;

namespace Swashbuckle.AspNetCore.Filters
{
internal class ExamplesConverter
{
private static readonly MediaTypeHeaderValue ApplicationXml = MediaTypeHeaderValue.Parse("application/xml; charset=utf-8");
private static readonly MediaTypeHeaderValue ApplicationJson = MediaTypeHeaderValue.Parse("application/json; charset=utf-8");

private readonly MvcOutputFormatter mvcOutputFormatter;

public ExamplesConverter(MvcOutputFormatter mvcOutputFormatter)
{
this.mvcOutputFormatter = mvcOutputFormatter;
}

public IOpenApiAny SerializeExampleXml(object value)
{
return new OpenApiString(mvcOutputFormatter.Serialize(value, ApplicationXml).FormatXml());
}

public IOpenApiAny SerializeExampleJson(object value)
public IOpenApiAny SerializeExample(object value, ExampleFormat format)
{
return new OpenApiRawString(mvcOutputFormatter.Serialize(value, ApplicationJson));
return format.Format(mvcOutputFormatter.Serialize(value, format.MimeType));
}

public IDictionary<string, OpenApiExample> ToOpenApiExamplesDictionaryXml(
IEnumerable<ISwaggerExample<object>> examples)
{
return ToOpenApiExamplesDictionary(examples, SerializeExampleXml);
}

public IDictionary<string, OpenApiExample> ToOpenApiExamplesDictionaryJson(
IEnumerable<ISwaggerExample<object>> examples)
public IDictionary<string, OpenApiExample> ToOpenApiExamplesDictionary(
IEnumerable<ISwaggerExample<object>> examples,
ExampleFormat format)
{
return ToOpenApiExamplesDictionary(examples, SerializeExampleJson);
return ToOpenApiExamplesDictionary(examples, x => SerializeExample(x, format));
}

private static IDictionary<string, OpenApiExample> ToOpenApiExamplesDictionary(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Microsoft.Net.Http.Headers;
using Microsoft.OpenApi.Any;

namespace Swashbuckle.AspNetCore.Filters.Examples
{
internal abstract class ExampleFormat
{
public ExampleFormat(string mime)
{
MimeType = MediaTypeHeaderValue.Parse(mime);
}

public MediaTypeHeaderValue MimeType { get; }

public virtual IOpenApiAny Format(string s)
{
return new OpenApiRawString(s);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Net.Http.Headers;

namespace Swashbuckle.AspNetCore.Filters.Examples
{
internal static class ExampleFormats
{
public static readonly ExampleFormat Xml = new XmlExampleFormat();
public static readonly ExampleFormat Json = new JsonExampleFormat();
public static readonly ExampleFormat Yaml = new YamlExampleFormat();

public static IEnumerable<ExampleFormat> All()
{
yield return Xml;
yield return Json;
yield return Yaml;
}

public static ExampleFormat GetFormat(string mime)
{
return All().FirstOrDefault(x => new MediaTypeHeaderValue(mime).IsSubsetOf(x.MimeType));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Swashbuckle.AspNetCore.Filters.Examples
{
internal class JsonExampleFormat : ExampleFormat
{
public JsonExampleFormat() : base("application/json") { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.OpenApi.Any;
using Swashbuckle.AspNetCore.Filters.Extensions;

namespace Swashbuckle.AspNetCore.Filters.Examples
{
internal class XmlExampleFormat : ExampleFormat
{
public XmlExampleFormat() : base("application/xml")
{

}

public override IOpenApiAny Format(string s)
{
return new OpenApiString(s.FormatXml());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.OpenApi.Any;

namespace Swashbuckle.AspNetCore.Filters.Examples
{
internal class YamlExampleFormat : ExampleFormat
{
public YamlExampleFormat() : base("application/yaml") { }

public override IOpenApiAny Format(string s)
{
return new OpenApiString(s);
}
}
}
39 changes: 12 additions & 27 deletions src/Swashbuckle.AspNetCore.Filters/Examples/RequestExample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Net.Http.Headers;
using Swashbuckle.AspNetCore.Filters.Examples;

namespace Swashbuckle.AspNetCore.Filters
{
Expand Down Expand Up @@ -78,19 +80,13 @@ private IOpenApiAny SetSingleRequestExampleForOperation(
object example,
ExamplesConverter examplesConverter)
{
var jsonExample = new Lazy<IOpenApiAny>(() => examplesConverter.SerializeExampleJson(example));
var xmlExample = new Lazy<IOpenApiAny>(() => examplesConverter.SerializeExampleXml(example));

foreach (var content in operation.RequestBody.Content)
{
if (content.Key.Contains("xml"))
{
content.Value.Example = xmlExample.Value;
}
else
{
content.Value.Example = jsonExample.Value;
}
var format = ExampleFormats.GetFormat(content.Key);
if (format == null)
continue; // fail more gracefully?

content.Value.Example = examplesConverter.SerializeExample(example, format);
}

return operation.RequestBody.Content.FirstOrDefault().Value?.Example;
Expand All @@ -105,24 +101,13 @@ private IOpenApiAny SetMultipleRequestExamplesForOperation(
IEnumerable<ISwaggerExample<object>> examples,
ExamplesConverter examplesConverter)
{
var jsonExamples = new Lazy<IDictionary<string, OpenApiExample>>(() =>
examplesConverter.ToOpenApiExamplesDictionaryJson(examples)
);

var xmlExamples = new Lazy<IDictionary<string, OpenApiExample>>(() =>
examplesConverter.ToOpenApiExamplesDictionaryXml(examples)
);

foreach (var content in operation.RequestBody.Content)
{
if (content.Key.Contains("xml"))
{
content.Value.Examples = xmlExamples.Value;
}
else
{
content.Value.Examples = jsonExamples.Value;
}
var format = ExampleFormats.GetFormat(content.Key);
if (format == null)
continue; // fail more gracefully?

content.Value.Examples = examplesConverter.ToOpenApiExamplesDictionary(examples, format);
}

return operation.RequestBody.Content.FirstOrDefault().Value?.Examples?.FirstOrDefault().Value?.Value;
Expand Down
39 changes: 12 additions & 27 deletions src/Swashbuckle.AspNetCore.Filters/Examples/ResponseExample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Swashbuckle.AspNetCore.Filters.Examples;

namespace Swashbuckle.AspNetCore.Filters
{
Expand Down Expand Up @@ -52,45 +53,29 @@ private void SetSingleResponseExampleForStatusCode(
object example,
ExamplesConverter examplesConverter)
{
var jsonExample = new Lazy<IOpenApiAny>(() => examplesConverter.SerializeExampleJson(example));
var xmlExample = new Lazy<IOpenApiAny>(() => examplesConverter.SerializeExampleXml(example));

foreach (var content in response.Value.Content)
{
if (content.Key.Contains("xml"))
{
content.Value.Example = xmlExample.Value;
}
else
{
content.Value.Example = jsonExample.Value;
}
var format = ExampleFormats.GetFormat(content.Key);
if (format == null)
continue; // fail more gracefully?

content.Value.Example = examplesConverter.SerializeExample(example, format);
}

}

private void SetMultipleResponseExampleForStatusCode(
KeyValuePair<string, OpenApiResponse> response,
IEnumerable<ISwaggerExample<object>> examples,
ExamplesConverter examplesConverter)
{
var jsonExamples = new Lazy<IDictionary<string, OpenApiExample>>(() =>
examplesConverter.ToOpenApiExamplesDictionaryJson(examples)
);

var xmlExamples = new Lazy<IDictionary<string, OpenApiExample>>(() =>
examplesConverter.ToOpenApiExamplesDictionaryXml(examples)
);

foreach (var content in response.Value.Content)
{
if (content.Key.Contains("xml"))
{
content.Value.Examples = xmlExamples.Value;
}
else
{
content.Value.Examples = jsonExamples.Value;
}
var format = ExampleFormats.GetFormat(content.Key);
if (format == null)
continue; // fail more gracefully?

content.Value.Examples = examplesConverter.ToOpenApiExamplesDictionary(examples, format);
}
}
}
Expand Down