Skip to content
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

.Net: DefaultValue for OpenAPI payload properties #4612

Merged
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ private static List<RestApiOperationParameter> GetParametersFromPayloadMetadata(
expand: false,
RestApiOperationParameterLocation.Body,
RestApiOperationParameterStyle.Simple,
defaultValue: property.DefaultValue,
description: property.Description,
schema: property.Schema));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public sealed class RestApiOperationParameter
/// <summary>
/// The default value.
/// </summary>
public string? DefaultValue { get; }
public object? DefaultValue { get; }

/// <summary>
/// Specifies whether arrays and objects should generate separate parameters for each array item or object property.
Expand Down Expand Up @@ -83,7 +83,7 @@ public RestApiOperationParameter(
RestApiOperationParameterLocation location,
RestApiOperationParameterStyle? style = null,
string? arrayItemType = null,
string? defaultValue = null,
object? defaultValue = null,
string? description = null,
KernelJsonSchema? schema = null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,28 +39,37 @@ public sealed class RestApiOperationPayloadProperty
/// </summary>
public KernelJsonSchema? Schema { get; }

/// <summary>
/// The default value.
/// </summary>
public object? DefaultValue { get; }

/// <summary>
/// Creates an instance of a <see cref="RestApiOperationPayloadProperty"/> class.
/// </summary>
/// <param name="name">Property name.</param>
/// <param name="type">Property type.</param>
/// <param name="isRequired">Flag specifying if the property is required or not.</param>
/// <param name="properties">Properties.</param>
/// <param name="description">Property description.</param>
/// <param name="name">The name of the property.</param>
/// <param name="type">The type of the property.</param>
/// <param name="isRequired">A flag specifying if the property is required or not.</param>
/// <param name="properties">A list of properties for the payload property.</param>
/// <param name="description">A description of the property.</param>
/// <param name="schema">The schema of the payload property.</param>
/// <param name="defaultValue">The default value of the property.</param>
/// <returns>Returns a new instance of the <see cref="RestApiOperationPayloadProperty"/> class.</returns>
public RestApiOperationPayloadProperty(
string name,
string type,
bool isRequired,
IList<RestApiOperationPayloadProperty> properties,
SergeyMenshykh marked this conversation as resolved.
Show resolved Hide resolved
string? description = null,
KernelJsonSchema? schema = null)
KernelJsonSchema? schema = null,
object? defaultValue = null)
{
this.Name = name;
this.Type = type;
this.IsRequired = isRequired;
this.Description = description;
this.Properties = properties;
this.Schema = schema;
this.DefaultValue = defaultValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
Expand Down Expand Up @@ -313,7 +312,8 @@ private static List<RestApiOperationPayloadProperty> GetPayloadProperties(string
requiredProperties.Contains(propertyName),
GetPayloadProperties(operationId, propertySchema, requiredProperties, level + 1),
propertySchema.Description,
propertySchema.ToJsonSchema());
propertySchema.ToJsonSchema(),
GetParameterValue(propertySchema.Default));

result.Add(property);
}
Expand All @@ -326,7 +326,7 @@ private static List<RestApiOperationPayloadProperty> GetPayloadProperties(string
/// </summary>
/// <param name="valueMetadata">The value metadata.</param>
/// <returns>The parameter value.</returns>
private static string? GetParameterValue(IOpenApiAny valueMetadata)
private static object? GetParameterValue(IOpenApiAny valueMetadata)
{
if (valueMetadata is not IOpenApiPrimitive value)
{
Expand All @@ -335,17 +335,17 @@ private static List<RestApiOperationPayloadProperty> GetPayloadProperties(string

return value.PrimitiveType switch
{
PrimitiveType.Integer => ((OpenApiInteger)value).Value.ToString(CultureInfo.InvariantCulture),
PrimitiveType.Long => ((OpenApiLong)value).Value.ToString(CultureInfo.InvariantCulture),
PrimitiveType.Float => ((OpenApiFloat)value).Value.ToString(CultureInfo.InvariantCulture),
PrimitiveType.Double => ((OpenApiDouble)value).Value.ToString(CultureInfo.InvariantCulture),
PrimitiveType.String => ((OpenApiString)value).Value.ToString(CultureInfo.InvariantCulture),
PrimitiveType.Byte => Convert.ToBase64String(((OpenApiByte)value).Value),
PrimitiveType.Binary => Encoding.UTF8.GetString(((OpenApiBinary)value).Value),
PrimitiveType.Boolean => ((OpenApiBoolean)value).Value.ToString(CultureInfo.InvariantCulture),
PrimitiveType.Date => ((OpenApiDate)value).Value.ToString("o").Substring(0, 10),
PrimitiveType.DateTime => ((OpenApiDateTime)value).Value.ToString(CultureInfo.InvariantCulture),
PrimitiveType.Password => ((OpenApiPassword)value).Value.ToString(CultureInfo.InvariantCulture),
PrimitiveType.Integer => ((OpenApiInteger)value).Value,
PrimitiveType.Long => ((OpenApiLong)value).Value,
PrimitiveType.Float => ((OpenApiFloat)value).Value,
PrimitiveType.Double => ((OpenApiDouble)value).Value,
PrimitiveType.String => ((OpenApiString)value).Value,
PrimitiveType.Byte => ((OpenApiByte)value).Value,
PrimitiveType.Binary => ((OpenApiBinary)value).Value,
PrimitiveType.Boolean => ((OpenApiBoolean)value).Value,
PrimitiveType.Date => ((OpenApiDate)value).Value,
PrimitiveType.DateTime => ((OpenApiDateTime)value).Value,
PrimitiveType.Password => ((OpenApiPassword)value).Value,
_ => throw new KernelException($"The value type - {value.PrimitiveType} is not supported."),
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,18 +280,53 @@ private static RestApiOperation CreateTestOperation(string method, RestApiOperat

private static RestApiOperationPayload CreateTestJsonPayload()
{
var name = new RestApiOperationPayloadProperty("name", "string", true, new List<RestApiOperationPayloadProperty>(), "The name.");

var leader = new RestApiOperationPayloadProperty("leader", "string", true, new List<RestApiOperationPayloadProperty>(), "The leader.");

var landmarks = new RestApiOperationPayloadProperty("landmarks", "array", false, new List<RestApiOperationPayloadProperty>(), "The landmarks.");
var location = new RestApiOperationPayloadProperty("location", "object", true, new[] { landmarks }, "The location.");

var rulingCouncil = new RestApiOperationPayloadProperty("rulingCouncil", "object", true, new[] { leader }, "The ruling council.");

var population = new RestApiOperationPayloadProperty("population", "integer", true, new List<RestApiOperationPayloadProperty>(), "The population.");

var hasMagicWards = new RestApiOperationPayloadProperty("hasMagicWards", "boolean", false, new List<RestApiOperationPayloadProperty>());
var name = new RestApiOperationPayloadProperty(
name: "name",
type: "string",
isRequired: true,
properties: new List<RestApiOperationPayloadProperty>(),
description: "The name.");

var leader = new RestApiOperationPayloadProperty(
name: "leader",
type: "string",
isRequired: true,
properties: new List<RestApiOperationPayloadProperty>(),
description: "The leader.");

var landmarks = new RestApiOperationPayloadProperty(
name: "landmarks",
type: "array",
isRequired: false,
properties: new List<RestApiOperationPayloadProperty>(),
description: "The landmarks.");

var location = new RestApiOperationPayloadProperty(
name: "location",
type: "object",
isRequired: true,
properties: new[] { landmarks },
description: "The location.");

var rulingCouncil = new RestApiOperationPayloadProperty(
name: "rulingCouncil",
type: "object",
isRequired: true,
properties: new[] { leader },
description: "The ruling council.");

var population = new RestApiOperationPayloadProperty(
name: "population",
type: "integer",
isRequired: true,
properties: new List<RestApiOperationPayloadProperty>(),
description: "The population.");

var hasMagicWards = new RestApiOperationPayloadProperty(
name: "hasMagicWards",
type: "boolean",
isRequired: false,
properties: new List<RestApiOperationPayloadProperty>());

return new RestApiOperationPayload("application/json", new[] { name, location, rulingCouncil, population, hasMagicWards });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public async Task ItCanExtractSimpleTypeHeaderParameterMetadataSuccessfullyAsync
var apiVersion = GetParameterMetadata(operations, "SetSecret", RestApiOperationParameterLocation.Header, "X-API-Version");

Assert.Equal("integer", apiVersion.Type);
Assert.Equal("10", apiVersion.DefaultValue);
Assert.Equal(10, apiVersion.DefaultValue);
Assert.Equal("Requested API version.", apiVersion.Description);
Assert.True(apiVersion.IsRequired);
}
Expand Down Expand Up @@ -225,7 +225,7 @@ public async Task ItCanExtractAllPathsAsOperationsAsync()
var operations = await this._sut.ParseAsync(this._openApiDocument);

// Assert
Assert.Equal(3, operations.Count);
Assert.Equal(4, operations.Count);
}

[Fact]
Expand Down Expand Up @@ -293,6 +293,65 @@ public async Task ItCanParseResponsesSuccessfullyAsync()
JsonSerializer.Serialize(response.Schema));
}

[Fact]
public async Task ItCanWorkWithDefaultParametersOfVariousTypesAsync()
{
//Act
var operations = await this._sut.ParseAsync(this._openApiDocument);

//Assert
Assert.NotNull(operations);
Assert.True(operations.Any());

var operation = operations.Single(o => o.Id == "TestDefaultValues");
Assert.NotNull(operation);

var parameters = operation.GetParameters();
Assert.Equal(11, parameters.Count);

var stringParameter = parameters.Single(p => p.Name == "string-parameter");
Assert.Equal("string-value", stringParameter.DefaultValue);

var booleanParameter = parameters.Single(p => p.Name == "boolean-parameter");
Assert.True(booleanParameter.DefaultValue is bool value);

var integerParameter = parameters.Single(p => p.Name == "integer-parameter");
Assert.True(integerParameter.DefaultValue is int);
Assert.Equal(281, integerParameter.DefaultValue);

var longParameter = parameters.Single(p => p.Name == "long-parameter");
Assert.True(longParameter.DefaultValue is long);
Assert.Equal((long)-2814, longParameter.DefaultValue);

var floatParameter = parameters.Single(p => p.Name == "float-parameter");
Assert.True(floatParameter.DefaultValue is float);
Assert.Equal((float)12.01, floatParameter.DefaultValue);

var doubleParameter = parameters.Single(p => p.Name == "double-parameter");
Assert.True(doubleParameter.DefaultValue is double);
Assert.Equal((double)-12.01, doubleParameter.DefaultValue);

var encodedCharactersParameter = parameters.Single(p => p.Name == "encoded-characters-parameter");
Assert.True(encodedCharactersParameter.DefaultValue is byte[]);
Assert.Equal(new byte[] { 1, 2, 3, 4, 5 }, encodedCharactersParameter.DefaultValue);

var binaryDataParameter = parameters.Single(p => p.Name == "binary-data-parameter");
Assert.True(binaryDataParameter.DefaultValue is byte[]);
Assert.Equal(new byte[] { 50, 51, 52, 53, 54 }, binaryDataParameter.DefaultValue);

var dateParameter = parameters.Single(p => p.Name == "date-parameter");
Assert.True(dateParameter.DefaultValue is DateTime);
Assert.Equal(new DateTime(2017, 07, 21), dateParameter.DefaultValue);

var dateTimeParameter = parameters.Single(p => p.Name == "date-time-parameter");
Assert.True(dateTimeParameter.DefaultValue is DateTimeOffset);
Assert.Equal(new DateTimeOffset(2017, 07, 21, 17, 32, 28, TimeSpan.Zero), dateTimeParameter.DefaultValue);

var passwordParameter = parameters.Single(p => p.Name == "password-parameter");
Assert.True(passwordParameter.DefaultValue is string);
Assert.Equal("password-value", passwordParameter.DefaultValue);
}

private static RestApiOperationParameter GetParameterMetadata(IList<RestApiOperation> operations, string operationId,
RestApiOperationParameterLocation location, string name)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public async Task ItCanExtractSimpleTypeHeaderParameterMetadataSuccessfullyAsync
var apiVersion = GetParameterMetadata(operations, "SetSecret", RestApiOperationParameterLocation.Header, "X-API-Version");

Assert.Equal("integer", apiVersion.Type);
Assert.Equal("10", apiVersion.DefaultValue);
Assert.Equal(10, apiVersion.DefaultValue);
Assert.Equal("Requested API version.", apiVersion.Description);
Assert.True(apiVersion.IsRequired);
}
Expand Down Expand Up @@ -226,7 +226,7 @@ public async Task ItCanExtractAllPathsAsOperationsAsync()
var operations = await this._sut.ParseAsync(this._openApiDocument);

// Assert
Assert.Equal(3, operations.Count);
Assert.Equal(4, operations.Count);
}

[Fact]
Expand Down Expand Up @@ -366,6 +366,65 @@ public async Task ItCanParseResponsesSuccessfullyAsync()
JsonSerializer.Serialize(response.Schema));
}

[Fact]
public async Task ItCanWorkWithDefaultParametersOfVariousTypesAsync()
{
//Act
var operations = await this._sut.ParseAsync(this._openApiDocument);

//Assert
Assert.NotNull(operations);
Assert.True(operations.Any());

var operation = operations.Single(o => o.Id == "TestDefaultValues");
Assert.NotNull(operation);

var parameters = operation.GetParameters();
Assert.Equal(11, parameters.Count);

var stringParameter = parameters.Single(p => p.Name == "string-parameter");
Assert.Equal("string-value", stringParameter.DefaultValue);

var booleanParameter = parameters.Single(p => p.Name == "boolean-parameter");
Assert.True(booleanParameter.DefaultValue is bool value);

var integerParameter = parameters.Single(p => p.Name == "integer-parameter");
Assert.True(integerParameter.DefaultValue is int);
Assert.Equal(281, integerParameter.DefaultValue);

var longParameter = parameters.Single(p => p.Name == "long-parameter");
Assert.True(longParameter.DefaultValue is long);
Assert.Equal((long)-2814, longParameter.DefaultValue);

var floatParameter = parameters.Single(p => p.Name == "float-parameter");
Assert.True(floatParameter.DefaultValue is float);
Assert.Equal((float)12.01, floatParameter.DefaultValue);

var doubleParameter = parameters.Single(p => p.Name == "double-parameter");
Assert.True(doubleParameter.DefaultValue is double);
Assert.Equal((double)-12.01, doubleParameter.DefaultValue);

var encodedCharactersParameter = parameters.Single(p => p.Name == "encoded-characters-parameter");
Assert.True(encodedCharactersParameter.DefaultValue is byte[]);
Assert.Equal(new byte[] { 1, 2, 3, 4, 5 }, encodedCharactersParameter.DefaultValue);

var binaryDataParameter = parameters.Single(p => p.Name == "binary-data-parameter");
Assert.True(binaryDataParameter.DefaultValue is byte[]);
Assert.Equal(new byte[] { 50, 51, 52, 53, 54 }, binaryDataParameter.DefaultValue);

var dateParameter = parameters.Single(p => p.Name == "date-parameter");
Assert.True(dateParameter.DefaultValue is DateTime);
Assert.Equal(new DateTime(2017, 07, 21), dateParameter.DefaultValue);

var dateTimeParameter = parameters.Single(p => p.Name == "date-time-parameter");
Assert.True(dateTimeParameter.DefaultValue is DateTimeOffset);
Assert.Equal(new DateTimeOffset(2017, 07, 21, 17, 32, 28, TimeSpan.Zero), dateTimeParameter.DefaultValue);

var passwordParameter = parameters.Single(p => p.Name == "password-parameter");
Assert.True(passwordParameter.DefaultValue is string);
Assert.Equal("password-value", passwordParameter.DefaultValue);
}

private static MemoryStream ModifyOpenApiDocument(Stream openApiDocument, Action<JsonObject> transformer)
{
var json = JsonSerializer.Deserialize<JsonObject>(openApiDocument);
Expand Down
Loading
Loading