Revert changes to WireMock.Net.OpenApiParser (#1289)

* Revert changes to WireMock.Net.OpenApiParser

* revert
This commit is contained in:
Stef Heyenrath
2025-05-02 07:18:35 +02:00
committed by GitHub
parent e7310fbc7b
commit cf0dcf5855
36 changed files with 1909 additions and 644 deletions

View File

@@ -3,19 +3,20 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.OpenApi;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Models.Interfaces;
using Microsoft.OpenApi.Writers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Stef.Validation;
using WireMock.Admin.Mappings;
using WireMock.Net.OpenApiParser.Extensions;
using WireMock.Net.OpenApiParser.Settings;
using WireMock.Net.OpenApiParser.Types;
using WireMock.Net.OpenApiParser.Utils;
using SystemTextJsonSerializer = System.Text.Json.JsonSerializer;
namespace WireMock.Net.OpenApiParser.Mappers;
@@ -38,40 +39,56 @@ internal class OpenApiPathsMapper
.OrderBy(p => p.Key)
.Select(p => MapPath(p.Key, p.Value, servers))
.SelectMany(x => x)
.ToArray() ?? [];
.ToArray() ??
Array.Empty<MappingModel>();
}
private IReadOnlyList<MappingModel> MapPath(string path, IOpenApiPathItem pathItem, IList<OpenApiServer> servers)
private IReadOnlyList<MappingModel> MapPaths(OpenApiPaths? paths, IList<OpenApiServer> servers)
{
return pathItem.Operations?.Select(o => MapOperationToMappingModel(path, o.Key.ToString().ToUpperInvariant(), o.Value, servers)).ToArray() ?? [];
return paths?
.OrderBy(p => p.Key)
.Select(p => MapPath(p.Key, p.Value, servers))
.SelectMany(x => x)
.ToArray() ??
Array.Empty<MappingModel>();
}
private IReadOnlyList<MappingModel> MapPath(string path, OpenApiPathItem pathItem, IList<OpenApiServer> servers)
{
return pathItem.Operations.Select(o => MapOperationToMappingModel(path, o.Key.ToString().ToUpperInvariant(), o.Value, servers)).ToArray();
}
private MappingModel MapOperationToMappingModel(string path, string httpMethod, OpenApiOperation operation, IList<OpenApiServer> servers)
{
var queryParameters = operation.Parameters?.Where(p => p.In == ParameterLocation.Query) ?? [];
var pathParameters = operation.Parameters?.Where(p => p.In == ParameterLocation.Path) ?? [];
var headers = operation.Parameters?.Where(p => p.In == ParameterLocation.Header) ?? [];
var queryParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Query);
var pathParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Path);
var headers = operation.Parameters.Where(p => p.In == ParameterLocation.Header);
var response = operation?.Responses?.FirstOrDefault() ?? new KeyValuePair<string, IOpenApiResponse>();
var response = operation.Responses.FirstOrDefault();
TryGetContent(response.Value?.Content, out OpenApiMediaType? responseContent, out var responseContentType);
TryGetContent(response.Value?.Content, out OpenApiMediaType? responseContent, out string? responseContentType);
var responseSchema = response.Value?.Content?.FirstOrDefault().Value?.Schema;
var responseExample = responseContent?.Example;
var responseSchemaExample = responseContent?.Schema?.Example;
var responseBody = responseExample ?? responseSchemaExample ?? MapSchemaToObject(responseSchema);
var body = responseExample != null ? MapOpenApiAnyToJToken(responseExample) :
responseSchemaExample != null ? MapOpenApiAnyToJToken(responseSchemaExample) :
MapSchemaToObject(responseSchema);
var requestBodyModel = new BodyModel();
if (operation.RequestBody != null && operation.RequestBody.Content != null && operation.RequestBody.Required)
{
var request = operation.RequestBody.Content;
TryGetContent(request, out var requestContent, out _);
TryGetContent(request, out OpenApiMediaType? requestContent, out _);
var requestBodySchema = operation.RequestBody.Content.First().Value?.Schema;
var requestBodyExample = requestContent!.Example;
var requestBodySchemaExample = requestContent.Schema?.Example;
var requestBodyMapped = requestBodyExample ?? requestBodySchemaExample ?? MapSchemaToObject(requestBodySchema);
var requestBodyMapped = requestBodyExample != null ? MapOpenApiAnyToJToken(requestBodyExample) :
requestBodySchemaExample != null ? MapOpenApiAnyToJToken(requestBodySchemaExample) :
MapSchemaToObject(requestBodySchema);
requestBodyModel = MapRequestBody(requestBodyMapped);
}
@@ -95,12 +112,12 @@ internal class OpenApiPathsMapper
{
StatusCode = httpStatusCode,
Headers = MapHeaders(responseContentType, response.Value?.Headers),
BodyAsJson = responseBody != null ? JsonConvert.DeserializeObject(SystemTextJsonSerializer.Serialize(responseBody)) : null
BodyAsJson = body
}
};
}
private BodyModel? MapRequestBody(JsonNode? requestBody)
private BodyModel? MapRequestBody(object? requestBody)
{
if (requestBody == null)
{
@@ -112,7 +129,7 @@ internal class OpenApiPathsMapper
Matcher = new MatcherModel
{
Name = "JsonMatcher",
Pattern = SystemTextJsonSerializer.Serialize(requestBody, new JsonSerializerOptions { WriteIndented = true }),
Pattern = JsonConvert.SerializeObject(requestBody, Formatting.Indented),
IgnoreCase = _settings.RequestBodyIgnoreCase
}
};
@@ -143,103 +160,117 @@ internal class OpenApiPathsMapper
return true;
}
private JsonNode? MapSchemaToObject(IOpenApiSchema? schema)
private object? MapSchemaToObject(OpenApiSchema? schema, string? name = null)
{
if (schema == null)
{
return null;
}
switch (schema.GetSchemaType(out _))
switch (schema.GetSchemaType())
{
case JsonSchemaType.Array:
var array = new JsonArray();
for (var i = 0; i < _settings.NumberOfArrayItems; i++)
case SchemaType.Array:
var jArray = new JArray();
for (int i = 0; i < _settings.NumberOfArrayItems; i++)
{
if (schema.Items?.Properties?.Count > 0)
if (schema.Items.Properties.Count > 0)
{
var item = new JsonObject();
var arrayItem = new JObject();
foreach (var property in schema.Items.Properties)
{
item[property.Key] = MapSchemaToObject(property.Value);
var objectValue = MapSchemaToObject(property.Value, property.Key);
if (objectValue is JProperty jp)
{
arrayItem.Add(jp);
}
else
{
arrayItem.Add(new JProperty(property.Key, objectValue));
}
}
array.Add(item);
jArray.Add(arrayItem);
}
else
{
var arrayItem = MapSchemaToObject(schema.Items);
array.Add(arrayItem);
var arrayItem = MapSchemaToObject(schema.Items, name: null); // Set name to null to force JObject instead of JProperty
jArray.Add(arrayItem);
}
}
if (schema.AllOf?.Count > 0)
if (schema.AllOf.Count > 0)
{
array.Add(MapSchemaAllOfToObject(schema));
jArray.Add(MapSchemaAllOfToObject(schema));
}
return array;
return jArray;
case JsonSchemaType.Boolean:
case JsonSchemaType.Integer:
case JsonSchemaType.Number:
case JsonSchemaType.String:
case SchemaType.Boolean:
case SchemaType.Integer:
case SchemaType.Number:
case SchemaType.String:
return _exampleValueGenerator.GetExampleValue(schema);
case JsonSchemaType.Object:
var propertyAsJsonObject = new JsonObject();
foreach (var schemaProperty in schema.Properties ?? new Dictionary<string, IOpenApiSchema>())
case SchemaType.Object:
var propertyAsJObject = new JObject();
foreach (var schemaProperty in schema.Properties)
{
propertyAsJsonObject[schemaProperty.Key] = MapPropertyAsJsonNode(schemaProperty.Value);
propertyAsJObject.Add(MapPropertyAsJObject(schemaProperty.Value, schemaProperty.Key));
}
if (schema.AllOf?.Count > 0)
if (schema.AllOf.Count > 0)
{
foreach (var group in schema.AllOf.SelectMany(p => p.Properties ?? new Dictionary<string, IOpenApiSchema>()).GroupBy(x => x.Key))
foreach (var group in schema.AllOf.SelectMany(p => p.Properties).GroupBy(x => x.Key))
{
propertyAsJsonObject[group.Key] = MapPropertyAsJsonNode(group.First().Value);
propertyAsJObject.Add(MapPropertyAsJObject(group.First().Value, group.Key));
}
}
return propertyAsJsonObject;
return name != null ? new JProperty(name, propertyAsJObject) : propertyAsJObject;
default:
return null;
}
}
private JsonObject MapSchemaAllOfToObject(IOpenApiSchema schema)
private JObject MapSchemaAllOfToObject(OpenApiSchema schema)
{
var arrayItem = new JsonObject();
foreach (var property in schema.AllOf ?? [])
var arrayItem = new JObject();
foreach (var property in schema.AllOf)
{
foreach (var item in property.Properties ?? new Dictionary<string, IOpenApiSchema>())
foreach (var item in property.Properties)
{
arrayItem[item.Key] = MapPropertyAsJsonNode(item.Value);
arrayItem.Add(MapPropertyAsJObject(item.Value, item.Key));
}
}
return arrayItem;
}
private JsonNode? MapPropertyAsJsonNode(IOpenApiSchema openApiSchema)
private object MapPropertyAsJObject(OpenApiSchema openApiSchema, string key)
{
var schemaType = openApiSchema.GetSchemaType(out _);
if (schemaType is JsonSchemaType.Object or JsonSchemaType.Array)
if (openApiSchema.GetSchemaType() == SchemaType.Object || openApiSchema.GetSchemaType() == SchemaType.Array)
{
return MapSchemaToObject(openApiSchema);
var mapped = MapSchemaToObject(openApiSchema, key);
if (mapped is JProperty jp)
{
return jp;
}
return new JProperty(key, mapped);
}
return _exampleValueGenerator.GetExampleValue(openApiSchema);
// bool propertyIsNullable = openApiSchema.Nullable || (openApiSchema.TryGetXNullable(out bool x) && x);
return new JProperty(key, _exampleValueGenerator.GetExampleValue(openApiSchema));
}
private string MapPathWithParameters(string path, IEnumerable<IOpenApiParameter>? parameters)
private string MapPathWithParameters(string path, IEnumerable<OpenApiParameter>? parameters)
{
if (parameters == null)
{
return path;
}
var newPath = path;
string newPath = path;
foreach (var parameter in parameters)
{
var exampleMatcherModel = GetExampleMatcherModel(parameter.Schema, _settings.PathPatternToUse);
@@ -249,56 +280,93 @@ internal class OpenApiPathsMapper
return newPath;
}
private IDictionary<string, object>? MapHeaders(string? responseContentType, IDictionary<string, IOpenApiHeader>? headers)
private string MapBasePath(IList<OpenApiServer>? servers)
{
var mappedHeaders = headers?
.ToDictionary(item => item.Key, _ => GetExampleMatcherModel(null, _settings.HeaderPatternToUse).Pattern!) ?? new Dictionary<string, object>();
if (servers == null || servers.Count == 0)
{
return string.Empty;
}
OpenApiServer server = servers.First();
if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out Uri uriResult))
{
return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
}
return string.Empty;
}
private JToken? MapOpenApiAnyToJToken(IOpenApiAny? any)
{
if (any == null)
{
return null;
}
using var outputString = new StringWriter();
var writer = new OpenApiJsonWriter(outputString);
any.Write(writer, OpenApiSpecVersion.OpenApi3_0);
if (any.AnyType == AnyType.Array)
{
return JArray.Parse(outputString.ToString());
}
return JObject.Parse(outputString.ToString());
}
private IDictionary<string, object>? MapHeaders(string? responseContentType, IDictionary<string, OpenApiHeader>? headers)
{
var mappedHeaders = headers?.ToDictionary(
item => item.Key,
_ => GetExampleMatcherModel(null, _settings.HeaderPatternToUse).Pattern!
) ?? new Dictionary<string, object>();
if (!string.IsNullOrEmpty(responseContentType))
{
mappedHeaders.TryAdd(HeaderContentType, responseContentType);
mappedHeaders.TryAdd(HeaderContentType, responseContentType!);
}
return mappedHeaders.Keys.Any() ? mappedHeaders : null;
}
private IList<ParamModel>? MapQueryParameters(IEnumerable<IOpenApiParameter> queryParameters)
private IList<ParamModel>? MapQueryParameters(IEnumerable<OpenApiParameter> queryParameters)
{
var list = queryParameters
.Where(req => req.Required)
.Select(qp => new ParamModel
{
Name = qp.Name ?? string.Empty,
Name = qp.Name,
IgnoreCase = _settings.QueryParameterPatternIgnoreCase,
Matchers =
[
Matchers = new[]
{
GetExampleMatcherModel(qp.Schema, _settings.QueryParameterPatternToUse)
]
}
})
.ToList();
return list.Any() ? list : null;
}
private IList<HeaderModel>? MapRequestHeaders(IEnumerable<IOpenApiParameter> headers)
private IList<HeaderModel>? MapRequestHeaders(IEnumerable<OpenApiParameter> headers)
{
var list = headers
.Where(req => req.Required)
.Select(qp => new HeaderModel
{
Name = qp.Name ?? string.Empty,
Name = qp.Name,
IgnoreCase = _settings.HeaderPatternIgnoreCase,
Matchers =
[
Matchers = new[]
{
GetExampleMatcherModel(qp.Schema, _settings.HeaderPatternToUse)
]
}
})
.ToList();
return list.Any() ? list : null;
}
private MatcherModel GetExampleMatcherModel(IOpenApiSchema? schema, ExampleValueType type)
private MatcherModel GetExampleMatcherModel(OpenApiSchema? schema, ExampleValueType type)
{
return type switch
{
@@ -317,31 +385,15 @@ internal class OpenApiPathsMapper
};
}
private string GetExampleValueAsStringForSchemaType(IOpenApiSchema? schema)
private string GetExampleValueAsStringForSchemaType(OpenApiSchema? schema)
{
var value = _exampleValueGenerator.GetExampleValue(schema);
if (value.GetValueKind() == JsonValueKind.String)
return value switch
{
return value.GetValue<string>();
}
string valueAsString => valueAsString,
return value.ToString();
}
private static string MapBasePath(IList<OpenApiServer>? servers)
{
var server = servers?.FirstOrDefault();
if (server == null)
{
return string.Empty;
}
if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out var uriResult))
{
return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
}
return string.Empty;
_ => value.ToString(),
};
}
}