Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reflection;
Expand All @@ -11,8 +12,13 @@
using Microsoft.OpenApi;
using Microsoft.OpenApi.Models;

using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

using YamlDotNet.Serialization;

using GenericExtensions = Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions.GenericExtensions;
using HttpRequestDataObjectExtensions = Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions.HttpRequestDataObjectExtensions;
using OpenApiDocumentExtensions = Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions.OpenApiDocumentExtensions;
Expand Down Expand Up @@ -43,7 +49,6 @@ public Document(IDocumentHelper helper)
public Document(OpenApiDocument openApiDocument)
{
this.OpenApiDocument = openApiDocument;

}

/// <inheritdoc />
Expand Down Expand Up @@ -173,7 +178,7 @@ public IDocument Build(Assembly assembly, OpenApiVersionType version = OpenApiVe
}

operation.Security = this._helper.GetOpenApiSecurityRequirement(method, this._strategy);
operation.Parameters = this._helper.GetOpenApiParameters(method, trigger, this._strategy, this._collection);
operation.Parameters = this._helper.GetOpenApiParameters(method, trigger, this._strategy, this._collection, version);
operation.RequestBody = this._helper.GetOpenApiRequestBody(method, this._strategy, this._collection, version);
operation.Responses = this._helper.GetOpenApiResponses(method, this._strategy, this._collection, version);

Expand Down Expand Up @@ -208,12 +213,64 @@ public async Task<string> RenderAsync(OpenApiSpecVersion version, OpenApiFormat

private string Render(OpenApiSpecVersion version, OpenApiFormat format)
{
//var serialised = default(string);
//using (var sw = new StringWriter())
//{
// OpenApiDocumentExtensions.Serialise(this.OpenApiDocument, sw, version, format);
// serialised = sw.ToString();
//}

//return serialised;

// This is the interim solution to resolve:
// https://github.com/Azure/azure-functions-openapi-extension/issues/365
//
// It will be removed when the following issue is resolved:
// https://github.com/microsoft/OpenAPI.NET/issues/747
var jserialised = default(string);
using (var sw = new StringWriter())
{
OpenApiDocumentExtensions.Serialise(this.OpenApiDocument, sw, version, OpenApiFormat.Json);
jserialised = sw.ToString();
}

var yserialised = default(string);
using (var sw = new StringWriter())
{
OpenApiDocumentExtensions.Serialise(this.OpenApiDocument, sw, version, format);
OpenApiDocumentExtensions.Serialise(this.OpenApiDocument, sw, version, OpenApiFormat.Yaml);
yserialised = sw.ToString();
}

if (version != OpenApiSpecVersion.OpenApi2_0)
{
return format == OpenApiFormat.Json ? jserialised : yserialised;
}

var jo = JsonConvert.DeserializeObject<JObject>(jserialised);
var jts = jo.DescendantsAndSelf()
.Where(p => p.Type == JTokenType.Property && (p as JProperty).Name == "parameters")
.SelectMany(p => p.Values<JArray>().SelectMany(q => q.Children<JObject>()))
.Where(p => p.Value<string>("in") == null)
.Where(p => p.Value<string>("description") != null)
.Where(p => p.Value<string>("description").Contains("[formData]"))
.ToList();
foreach (var jt in jts)
{
jt["in"] = "formData";
jt["description"] = jt.Value<string>("description").Replace("[formData]", string.Empty);
}

return sw.ToString();
var serialised = JsonConvert.SerializeObject(jo, Formatting.Indented);
if (format == OpenApiFormat.Json)
{
return serialised;
}

var converter = new ExpandoObjectConverter();
var deserialised = JsonConvert.DeserializeObject<ExpandoObject>(serialised, converter);
serialised = new SerializerBuilder().Build().Serialize(deserialised);

return serialised;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,69 @@ public static OpenApiOperation GetOpenApiOperation(this IDocumentHelper helper,
/// <param name="trigger"><see cref="HttpTriggerAttribute"/> instance.</param>
/// <param name="namingStrategy"><see cref="NamingStrategy"/> instance to create the JSON schema from .NET Types.</param>
/// <param name="collection"><see cref="VisitorCollection"/> instance to process parameters.</param>
/// <param name="version"><see cref="OpenApiVersionType"/> value.</param>
/// <returns>List of <see cref="OpenApiParameter"/> instance.</returns>
public static List<OpenApiParameter> GetOpenApiParameters(this IDocumentHelper helper, MethodInfo element, HttpTriggerAttribute trigger, NamingStrategy namingStrategy, VisitorCollection collection)
public static List<OpenApiParameter> GetOpenApiParameters(this IDocumentHelper helper, MethodInfo element, HttpTriggerAttribute trigger, NamingStrategy namingStrategy, VisitorCollection collection, OpenApiVersionType version)
{
var parameters = element.GetCustomAttributes<OpenApiParameterAttribute>(inherit: false)
.Where(p => p.Deprecated == false)
.Select(p => p.ToOpenApiParameter(namingStrategy, collection))
.ToList();

// This is the interim solution to resolve:
// https://github.com/Azure/azure-functions-openapi-extension/issues/365
//
// It will be removed when the following issue is resolved:
// https://github.com/microsoft/OpenAPI.NET/issues/747
if (version == OpenApiVersionType.V3)
{
return parameters;
}

var attributes = element.GetCustomAttributes<OpenApiRequestBodyAttribute>(inherit: false);
if (!attributes.Any())
{
return parameters;
}

var contents = attributes.Where(p => p.Deprecated == false)
.Where(p => p.ContentType == "application/x-www-form-urlencoded" || p.ContentType == "multipart/form-data")
.Select(p => p.ToOpenApiMediaType(namingStrategy, collection, version));
if (!contents.Any())
{
return parameters;
}

var @ref = contents.First().Schema.Reference;
var schemas = helper.GetOpenApiSchemas(new[] { element }.ToList(), namingStrategy, collection);
var schema = schemas.SingleOrDefault(p => p.Key == @ref.Id);
if (schema.IsNullOrDefault())
{
return parameters;
}

var properties = schema.Value.Properties;
foreach (var property in properties)
{
var value = property.Value;
if ((value.Type == "string" && value.Format == "binary") || (value.Type == "string" && value.Format == "base64"))
{
value.Type = "file";
value.Format = null;
}

var parameter = new OpenApiParameter()
{
Name = property.Key,
Description = $"[formData]{value.Description}",
Required = bool.TryParse($"{value.Required}", out var result) ? result : false,
Deprecated = value.Deprecated,
Schema = value,
};

parameters.Add(parameter);
}

// // TODO: Should this be forcibly provided?
// // This needs to be provided separately.
// if (trigger.AuthLevel != AuthorizationLevel.Anonymous)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.12" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Core" Version="1.1.0" />
<!-- <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Abstractions" Version="1.0.0" /> -->
<PackageReference Include="YamlDotNet" Version="11.2.1" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Visitors;
using Microsoft.OpenApi.Models;

using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;

namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public static OpenApiOperation GetOpenApiOperation(this IDocumentHelper helper,
/// <param name="trigger"><see cref="HttpTriggerAttribute"/> instance.</param>
/// <param name="namingStrategy"><see cref="NamingStrategy"/> instance to create the JSON schema from .NET Types.</param>
/// <param name="collection"><see cref="VisitorCollection"/> instance to process parameters.</param>
/// <param name="version">OpenAPI spec version.</param>
/// <param name="version"><see cref="OpenApiVersionType"/> value.</param>
/// <returns>List of <see cref="OpenApiParameter"/> instance.</returns>
public static List<OpenApiParameter> GetOpenApiParameters(this IDocumentHelper helper, MethodInfo element, HttpTriggerAttribute trigger, NamingStrategy namingStrategy, VisitorCollection collection, OpenApiVersionType version)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
<PackageReference Include="System.Runtime.Handles" Version="4.3.0" />
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0" />
<PackageReference Include="YamlDotNet" Version="11.2.1" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.Azure.WebJobs.Script.Abstractions" Version="1.0.0-preview" />
<PackageReference Include="YamlDotNet" Version="11.2.1" />
</ItemGroup>

<ItemGroup>
Expand Down