Skip to content

Commit

Permalink
Support $ref in request-bodies
Browse files Browse the repository at this point in the history
  • Loading branch information
Elzo Lubbers committed Jan 31, 2024
1 parent 116c636 commit 76c9d50
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 19 deletions.
2 changes: 1 addition & 1 deletion src/NSwag.CodeGeneration/Models/OperationModelBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ public TParameterModel ContentParameter
/// <summary>Gets a value indicating whether the operation consumes 'application/x-www-form-urlencoded'.</summary>
public bool ConsumesFormUrlEncoded =>
_operation.ActualConsumes?.Any(c => c == "application/x-www-form-urlencoded") == true ||
_operation.RequestBody?.Content.Any(mt => mt.Key == "application/x-www-form-urlencoded") == true;
_operation.RequestBody?.ActualRequestBody.Content.Any(mt => mt.Key == "application/x-www-form-urlencoded") == true;

/// <summary>Gets the form parameters.</summary>
public IEnumerable<TParameterModel> FormParameters => Parameters.Where(p => p.Kind == OpenApiParameterKind.FormData);
Expand Down
14 changes: 14 additions & 0 deletions src/NSwag.Core/OpenApiComponents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ public OpenApiComponents(OpenApiDocument document)
};
Responses = responses;

var requestBodies = new ObservableDictionary<string, OpenApiRequestBody>();
requestBodies.CollectionChanged += (sender, args) =>
{
foreach (var path in RequestBodies.Values)
{
path.Parent = document;
}
};
RequestBodies = requestBodies;

var parameters = new ObservableDictionary<string, OpenApiParameter>();
parameters.CollectionChanged += (sender, args) =>
{
Expand Down Expand Up @@ -90,6 +100,10 @@ public OpenApiComponents(OpenApiDocument document)
[JsonProperty(PropertyName = "responses", DefaultValueHandling = DefaultValueHandling.Ignore)]
public IDictionary<string, OpenApiResponse> Responses { get; }

/// <summary>Gets or sets the request bodies which can be used for all operations.</summary>
[JsonProperty(PropertyName = "requestBodies", DefaultValueHandling = DefaultValueHandling.Ignore)]
public IDictionary<string, OpenApiRequestBody> RequestBodies { get; }

/// <summary>Gets or sets the parameters which can be used for all operations.</summary>
[JsonProperty(PropertyName = "parameters", DefaultValueHandling = DefaultValueHandling.Ignore)]
public IDictionary<string, OpenApiParameter> Parameters { get; }
Expand Down
5 changes: 5 additions & 0 deletions src/NSwag.Core/OpenApiDocument.Serialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ private static PropertyRenameAndIgnoreSerializerContractResolver CreateJsonSeria
resolver.IgnoreProperty(typeof(OpenApiDocument), "definitions");
resolver.IgnoreProperty(typeof(OpenApiDocument), "parameters");
resolver.IgnoreProperty(typeof(OpenApiDocument), "responses");
resolver.IgnoreProperty(typeof(OpenApiDocument), "requestBodies");
resolver.IgnoreProperty(typeof(OpenApiDocument), "securityDefinitions");

resolver.IgnoreProperty(typeof(OpenApiResponse), "schema");
Expand Down Expand Up @@ -210,5 +211,9 @@ private void UpdateServers(ICollection<OpenApiSchema> schemes, string host, stri
/// <summary>Gets or sets the security definitions (Swagger only).</summary>
[JsonProperty(PropertyName = "securityDefinitions", Order = 16, DefaultValueHandling = DefaultValueHandling.Ignore)]
public IDictionary<string, OpenApiSecurityScheme> SecurityDefinitions => Components.SecuritySchemes;

/// <summary>Gets or sets the request bodies which can be used for all operations (Swagger only).</summary>
[JsonProperty(PropertyName = "requestBodies", Order = 17, DefaultValueHandling = DefaultValueHandling.Ignore)]
public IDictionary<string, OpenApiRequestBody> RequestBodies => Components.RequestBodies;
}
}
4 changes: 2 additions & 2 deletions src/NSwag.Core/OpenApiMediaType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public JsonSchema Schema
set
{
_schema = value;
Parent?.Parent?.UpdateBodyParameter();
(Parent?.Parent as OpenApiOperation)?.UpdateBodyParameter();
}
}

Expand All @@ -41,7 +41,7 @@ public object Example
set
{
_example = value;
Parent?.Parent?.UpdateBodyParameter();
(Parent?.Parent as OpenApiOperation)?.UpdateBodyParameter();
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/NSwag.Core/OpenApiOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,12 @@ private OpenApiParameter CreateBodyParameter()
private void UpdateBodyParameter(OpenApiParameter parameter)
{
parameter.Kind = OpenApiParameterKind.Body;
parameter.Name = RequestBody.ActualName;
parameter.Position = RequestBody.Position;
parameter.Description = RequestBody.Description;
parameter.IsRequired = RequestBody.IsRequired;
parameter.Example = RequestBody.Content.FirstOrDefault().Value?.Example;
parameter.Schema = RequestBody.Content.FirstOrDefault().Value?.Schema;
parameter.Name = RequestBody.ActualRequestBody.ActualName;
parameter.Position = RequestBody.ActualRequestBody.Position;
parameter.Description = RequestBody.ActualRequestBody.Description;
parameter.IsRequired = RequestBody.ActualRequestBody.IsRequired;
parameter.Example = RequestBody.ActualRequestBody.Content.FirstOrDefault().Value?.Example;
parameter.Schema = RequestBody.ActualRequestBody.Content.FirstOrDefault().Value?.Schema;
}

private void UpdateRequestBody(NotifyCollectionChangedEventArgs args)
Expand Down
6 changes: 3 additions & 3 deletions src/NSwag.Core/OpenApiParameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ public bool IsXmlBodyParameter
var parent = Parent as OpenApiOperation;
var consumes = parent?.ActualConsumes?.Any() == true ?
parent.ActualConsumes :
parent?.RequestBody?.Content.Keys;
parent?.RequestBody?.ActualRequestBody.Content.Keys;

return consumes?.Any() == true &&
consumes.Any(p => p.Contains("application/xml")) &&
Expand Down Expand Up @@ -256,7 +256,7 @@ public bool IsBinaryBodyParameter
}
else
{
var consumes = parent?.RequestBody?.Content;
var consumes = parent?.RequestBody?.ActualRequestBody.Content;
return (consumes?.Any(p => p.Key == "multipart/form-data") == true ||
consumes?.Any(p => p.Value.Schema?.IsBinary != false) == true) &&
consumes.Any(p => p.Key.Contains("*/*") && p.Value.Schema?.IsBinary != true) == false &&
Expand Down Expand Up @@ -286,7 +286,7 @@ public bool HasBinaryBodyWithMultipleMimeTypes
}
else
{
var consumes = parent?.RequestBody?.Content;
var consumes = parent?.RequestBody?.ActualRequestBody.Content;
return consumes?.Any() == true &&
(consumes.Count() > 1 ||
consumes.Any(p => p.Key.Contains("*")));
Expand Down
42 changes: 35 additions & 7 deletions src/NSwag.Core/OpenApiRequestBody.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@

using System.Collections.Generic;
using Newtonsoft.Json;
using NJsonSchema.References;
using NSwag.Collections;

namespace NSwag
{
/// <summary>The OpenApi request body (OpenAPI only).</summary>
public class OpenApiRequestBody
public class OpenApiRequestBody : JsonReferenceBase<OpenApiRequestBody>, IJsonReference
{
private string _name;
private bool _isRequired;
Expand All @@ -31,13 +32,17 @@ public OpenApiRequestBody()
mediaType.Parent = this;
}
Parent?.UpdateBodyParameter();
(ActualRequestBody.Parent as OpenApiOperation)?.UpdateBodyParameter();
};
Content = content;
}

[JsonIgnore]
internal OpenApiOperation Parent { get; set; }
internal object Parent { get; set; }

/// <summary>Gets the actual request body, either this or the referenced request body.</summary>
[JsonIgnore]
public OpenApiRequestBody ActualRequestBody => Reference ?? this;

/// <summary>Gets or sets the name.</summary>
[JsonProperty(PropertyName = "x-name", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)]
Expand All @@ -47,7 +52,7 @@ public string Name
set
{
_name = value;
Parent?.UpdateBodyParameter();
(ActualRequestBody.Parent as OpenApiOperation)?.UpdateBodyParameter();
}
}

Expand All @@ -59,7 +64,7 @@ public string Description
set
{
_description = value;
Parent?.UpdateBodyParameter();
(ActualRequestBody.Parent as OpenApiOperation)?.UpdateBodyParameter();
}
}

Expand All @@ -75,7 +80,7 @@ public bool IsRequired
set
{
_isRequired = value;
Parent?.UpdateBodyParameter();
(ActualRequestBody.Parent as OpenApiOperation)?.UpdateBodyParameter();
}
}

Expand All @@ -87,12 +92,35 @@ public bool IsRequired
set
{
_position = value;
Parent?.UpdateBodyParameter();
(ActualRequestBody.Parent as OpenApiOperation)?.UpdateBodyParameter();
}
}

/// <summary>Gets the actual name of the request body parameter.</summary>
[JsonIgnore]
public string ActualName => string.IsNullOrEmpty(Name) ? "body" : Name;

#region Implementation of IJsonReference

[JsonIgnore]
IJsonReference IJsonReference.ActualObject => ActualRequestBody;

[JsonIgnore]
object IJsonReference.PossibleRoot => (Parent as OpenApiOperation)?.Parent?.Parent;

#endregion

public override OpenApiRequestBody Reference
{
get
{
return base.Reference;
}
set
{
base.Reference = value;
(Parent as OpenApiOperation)?.UpdateBodyParameter();
}
}
}
}

0 comments on commit 76c9d50

Please sign in to comment.