diff --git a/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V1Proxy/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V1Proxy.csproj b/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V1Proxy/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V1Proxy.csproj
index b3a4000..f9e4fe4 100644
--- a/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V1Proxy/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V1Proxy.csproj
+++ b/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V1Proxy/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V1Proxy.csproj
@@ -41,12 +41,4 @@
-
-
-
-
-
-
-
-
diff --git a/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2IoC/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2IoC.csproj b/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2IoC/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2IoC.csproj
index b383c41..a06b044 100644
--- a/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2IoC/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2IoC.csproj
+++ b/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2IoC/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2IoC.csproj
@@ -38,12 +38,4 @@
-
-
-
-
-
-
-
-
diff --git a/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2Static/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2Static.csproj b/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2Static/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2Static.csproj
index 0435ca0..39211af 100644
--- a/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2Static/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2Static.csproj
+++ b/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2Static/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V2Static.csproj
@@ -37,12 +37,4 @@
-
-
-
-
-
-
-
-
diff --git a/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3IoC/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3IoC.csproj b/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3IoC/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3IoC.csproj
index 251b82a..aba7872 100644
--- a/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3IoC/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3IoC.csproj
+++ b/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3IoC/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3IoC.csproj
@@ -38,12 +38,4 @@
-
-
-
-
-
-
-
-
diff --git a/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static.csproj b/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static.csproj
index 461c6ac..518b88f 100644
--- a/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static.csproj
+++ b/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static.csproj
@@ -47,12 +47,4 @@
-->
-
-
-
-
-
-
-
-
diff --git a/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/local.settings.json b/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/local.settings.json
index fd5c20f..2ffcd3e 100644
--- a/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/local.settings.json
+++ b/samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/local.settings.json
@@ -6,7 +6,10 @@
"AZURE_FUNCTION_PROXY_DISABLE_LOCAL_CALL": "true",
+ "OpenApi__HideSwaggerUI": "false",
"OpenApi__ApiKey": "",
+ "OpenApi__AuthLevel__Document": "Anonymous",
+ "OpenApi__AuthLevel__UI": "Anonymous",
"OpenApi__BackendProxyUrl": "http://localhost:7071"
}
}
diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Extensions/SwaggerUIExtensions.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Extensions/SwaggerUIExtensions.cs
index d55242b..77346b5 100644
--- a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Extensions/SwaggerUIExtensions.cs
+++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Extensions/SwaggerUIExtensions.cs
@@ -1,5 +1,6 @@
using System.Threading.Tasks;
+using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions
@@ -14,14 +15,15 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions
///
/// instance.
/// The endpoint of the Swagger document.
+ /// The authorisation level of the Swagger document.
/// API key of the HTTP endpoint to render OpenAPI document.
/// The OpenAPI UI in HTML.
- public static async Task RenderAsync(this Task ui, string endpoint, string authKey = null)
+ public static async Task RenderAsync(this Task ui, string endpoint, AuthorizationLevel authLevel = AuthorizationLevel.Anonymous, string authKey = null)
{
var instance = await ui.ThrowIfNullOrDefault().ConfigureAwait(false);
endpoint.ThrowIfNullOrWhiteSpace();
- return await instance.RenderAsync(endpoint, authKey).ConfigureAwait(false);
+ return await instance.RenderAsync(endpoint, authLevel, authKey).ConfigureAwait(false);
}
///
@@ -29,14 +31,15 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions
///
/// instance.
/// The endpoint of the OAuth2 Redirect page.
+ /// The authorisation level of the Swagger document.
/// API key of the HTTP endpoint to render OpenAPI document.
/// The OAuth2 Redirect page in HTML.
- public static async Task RenderOAuth2RedirectAsync(this Task ui, string endpoint, string authKey = null)
+ public static async Task RenderOAuth2RedirectAsync(this Task ui, string endpoint, AuthorizationLevel authLevel = AuthorizationLevel.Anonymous, string authKey = null)
{
var instance = await ui.ThrowIfNullOrDefault().ConfigureAwait(false);
endpoint.ThrowIfNullOrWhiteSpace();
- return await instance.RenderOAuth2RedirectAsync(endpoint, authKey).ConfigureAwait(false);
+ return await instance.RenderOAuth2RedirectAsync(endpoint, authLevel, authKey).ConfigureAwait(false);
}
}
}
diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/ISwaggerUI.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/ISwaggerUI.cs
index 5e1509a..c02a02d 100644
--- a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/ISwaggerUI.cs
+++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/ISwaggerUI.cs
@@ -2,6 +2,7 @@ using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
+using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.OpenApi.Models;
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions
@@ -46,16 +47,18 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions
/// Renders OpenAPI UI in HTML.
///
/// The endpoint of the Swagger document.
+ /// The authorisation level of the Swagger document.
/// API key of the HTTP endpoint to render OpenAPI document.
/// OpenAPI UI in HTML.
- Task RenderAsync(string endpoint, string authKey = null);
+ Task RenderAsync(string endpoint, AuthorizationLevel authLevel = AuthorizationLevel.Anonymous, string authKey = null);
///
/// Renders OAuth Redirect in HTML.
///
/// The endpoint of the OAuth2 Redirect page.
+ /// The authorisation level of the Swagger document.
/// API key of the HTTP endpoint to render OpenAPI document.
/// OAuth Redirect in HTML.
- Task RenderOAuth2RedirectAsync(string endpoint, string authKey = null);
+ Task RenderOAuth2RedirectAsync(string endpoint, AuthorizationLevel authLevel = AuthorizationLevel.Anonymous, string authKey = null);
}
}
diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/SwaggerUI.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/SwaggerUI.cs
index 72b6756..6793f98 100644
--- a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/SwaggerUI.cs
+++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/SwaggerUI.cs
@@ -1,9 +1,11 @@
+using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
+using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;
using Microsoft.OpenApi.Models;
@@ -125,32 +127,32 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core
}
///
- public async Task RenderAsync(string endpoint, string authKey = null)
+ public async Task RenderAsync(string endpoint, AuthorizationLevel authLevel = AuthorizationLevel.Anonymous, string authKey = null)
{
endpoint.ThrowIfNullOrWhiteSpace();
var html = await Task.Factory
- .StartNew(() => this.Render(endpoint, authKey))
+ .StartNew(() => this.Render(endpoint, authLevel, authKey))
.ConfigureAwait(false);
return html;
}
///
- public async Task RenderOAuth2RedirectAsync(string endpoint, string authKey = null)
+ public async Task RenderOAuth2RedirectAsync(string endpoint, AuthorizationLevel authLevel = AuthorizationLevel.Anonymous, string authKey = null)
{
var html = await Task.Factory
- .StartNew(() => this.RenderOAuth2Redirect(endpoint, authKey))
+ .StartNew(() => this.RenderOAuth2Redirect(endpoint, authLevel, authKey))
.ConfigureAwait(false);
return html;
}
- private string Render(string endpoint, string authKey = null)
+ private string Render(string endpoint, AuthorizationLevel authLevel = AuthorizationLevel.Anonymous, string authKey = null)
{
var swaggerUiTitle = $"{this._info.Title} - Swagger UI";
var swaggerUrl = $"{this._baseUrl.TrimEnd('/')}/{endpoint}";
- if (!string.IsNullOrWhiteSpace(authKey))
+ if (this.IsAuthKeyRequired(authLevel, authKey))
{
swaggerUrl += $"?code={authKey}";
}
@@ -167,10 +169,10 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core
}
///
- private string RenderOAuth2Redirect(string endpoint, string authKey = null)
+ private string RenderOAuth2Redirect(string endpoint, AuthorizationLevel authLevel = AuthorizationLevel.Anonymous, string authKey = null)
{
var pageUrl = $"{this._baseUrl.TrimEnd('/')}/{endpoint}";
- if (!string.IsNullOrWhiteSpace(authKey))
+ if (this.IsAuthKeyRequired(authLevel, authKey))
{
pageUrl += $"?code={authKey}";
}
@@ -179,5 +181,20 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core
return html;
}
+
+ private bool IsAuthKeyRequired(AuthorizationLevel authLevel = AuthorizationLevel.Anonymous, string authKey = null)
+ {
+ if (authLevel == AuthorizationLevel.Anonymous)
+ {
+ return false;
+ }
+
+ if (authKey.IsNullOrWhiteSpace())
+ {
+ throw new InvalidOperationException("API key is required to access OpenAPI document");
+ }
+
+ return true;
+ }
}
}
diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/Configurations/OpenApiAuthLevelSettings.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/Configurations/OpenApiAuthLevelSettings.cs
new file mode 100644
index 0000000..55c53d2
--- /dev/null
+++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/Configurations/OpenApiAuthLevelSettings.cs
@@ -0,0 +1,20 @@
+using Microsoft.Azure.WebJobs.Extensions.Http;
+
+namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Configurations
+{
+ ///
+ /// This represents the environment variable settings entity for OpenAPI document auth level.
+ ///
+ public class OpenApiAuthLevelSettings
+ {
+ ///
+ /// Gets or sets the value for OpenAPI document rendering endpoints.
+ ///
+ public virtual AuthorizationLevel? Document { get; set; }
+
+ ///
+ /// Gets or sets the value for Swagger UI page rendering endpoints.
+ ///
+ public virtual AuthorizationLevel? UI { get; set; }
+ }
+}
diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/Configurations/OpenApiSettings.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/Configurations/OpenApiSettings.cs
new file mode 100644
index 0000000..71883d2
--- /dev/null
+++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/Configurations/OpenApiSettings.cs
@@ -0,0 +1,28 @@
+namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Configurations
+{
+ ///
+ /// This represents the environment variable settings entity for OpenAPI document.
+ ///
+ public class OpenApiSettings
+ {
+ ///
+ /// Gets or sets the value indicating whether to hide the Swagger UI page or not.
+ ///
+ public virtual bool HideSwaggerUI { get; set; }
+
+ ///
+ /// Gets or sets the API key to access to OpenAPI document.
+ ///
+ public virtual string AuthKey { get; set; }
+
+ ///
+ /// Gets or sets the object.
+ ///
+ public virtual OpenApiAuthLevelSettings AuthLevel { get; set; }
+
+ ///
+ /// Gets or sets the backend URL for Azure Functions Proxy.
+ ///
+ public virtual string BackendProxyUrl { get; set; }
+ }
+}
diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/HttpBindingMetadata.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/HttpBindingMetadata.cs
new file mode 100644
index 0000000..96dd9ef
--- /dev/null
+++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/HttpBindingMetadata.cs
@@ -0,0 +1,68 @@
+using System.Collections.Generic;
+
+using Microsoft.Azure.WebJobs.Extensions.Http;
+using Microsoft.Azure.WebJobs.Script.Description;
+
+using Newtonsoft.Json;
+
+namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
+{
+ ///
+ /// This represents the metadata entity for HTTP trigger binding.
+ ///
+ public class HttpBindingMetadata
+ {
+ ///
+ /// Gets or sets the name of the binding parameter. Default value is req.
+ ///
+ [JsonRequired]
+ [JsonProperty("name")]
+ public virtual string Name { get; set; } = "req";
+
+ ///
+ /// Gets or sets the binding type. Default value is httpTrigger.
+ ///
+ [JsonRequired]
+ [JsonProperty("type")]
+ public virtual string Type { get; set; } = "httpTrigger";
+
+ ///
+ /// Gets or sets the binding direction. Default value is .
+ ///
+ [JsonRequired]
+ [JsonProperty("direction")]
+ public virtual BindingDirection Direction { get; set; } = BindingDirection.In;
+
+ ///
+ /// Gets or sets the binding data type.
+ ///
+ [JsonProperty("dataType", NullValueHandling = NullValueHandling.Ignore)]
+ public virtual DataType? DataType { get; set; }
+
+ ///
+ /// Gets or sets the HTTP endpoint route template.
+ ///
+ [JsonProperty("route", NullValueHandling = NullValueHandling.Ignore)]
+ public virtual string Route { get; set; }
+
+ ///
+ /// Gets or sets the webhook type, handled by the trigger.
+ ///
+ [JsonProperty("webHookType", NullValueHandling = NullValueHandling.Ignore)]
+ public virtual string WebHookType { get; set; }
+
+ ///
+ /// Gets or sets the HTTP endpoint authorisation level. Default value is .
+ ///
+ [JsonRequired]
+ [JsonProperty("authLevel")]
+ public virtual AuthorizationLevel AuthLevel { get; set; } = AuthorizationLevel.Function;
+
+ ///
+ /// Gets or sets the list of the HTTP verbs. Default values are GET and POST.
+ ///
+ [JsonRequired]
+ [JsonProperty("methods")]
+ public virtual List Methods { get; set; } = new List() { "GET", "POST" };
+ }
+}
diff --git a/templates/OpenApiEndpoints/IOpenApiHttpTriggerContext.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/IOpenApiHttpTriggerContext.cs
similarity index 75%
rename from templates/OpenApiEndpoints/IOpenApiHttpTriggerContext.cs
rename to src/Microsoft.Azure.WebJobs.Extensions.OpenApi/IOpenApiHttpTriggerContext.cs
index 1d8bd3b..fa8601f 100644
--- a/templates/OpenApiEndpoints/IOpenApiHttpTriggerContext.cs
+++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/IOpenApiHttpTriggerContext.cs
@@ -1,6 +1,7 @@
using System;
using System.Reflection;
+using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
@@ -56,6 +57,11 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
///
NamingStrategy NamingStrategy { get; }
+ ///
+ /// Gets the value indicating whether it's in the development environment or not.
+ ///
+ bool IsDevelopment { get; }
+
///
/// Gets the executing assembly.
///
@@ -63,6 +69,13 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
[Obsolete("This method is obsolete.", error: true)]
Assembly GetExecutingAssembly();
+ ///
+ /// Sets the application assembly from the function app directory.
+ ///
+ /// Function app directory.
+ /// Value indicating whether to append the "bin" directory or not.
+ IOpenApiHttpTriggerContext SetApplicationAssembly(string functionAppDirectory, bool appendBin = true);
+
///
/// Gets the instance.
///
@@ -97,6 +110,20 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
/// Returns the value.
OpenApiFormat GetOpenApiFormat(OpenApiFormatType format = OpenApiFormatType.Json);
+ ///
+ /// Gets the auth level of the document rendering page endpoint.
+ ///
+ /// Environment variables key to look for.
+ /// Returns the auth level of the document rendering page endpoint.
+ AuthorizationLevel GetDocumentAuthLevel(string key = "OpenApi__AuthLevel__Document");
+
+ ///
+ /// Gets the auth level of the UI rendering page endpoint.
+ ///
+ /// Environment variables key to look for.
+ /// Returns the auth level of the UI rendering page endpoint.
+ AuthorizationLevel GetUIAuthLevel(string key = "OpenApi__AuthLevel__UI");
+
///
/// Gets the API key for endpoints from environment variables.
///
diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/Microsoft.Azure.WebJobs.Extensions.OpenApi.csproj b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/Microsoft.Azure.WebJobs.Extensions.OpenApi.csproj
index d073d4a..c82aeb3 100644
--- a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/Microsoft.Azure.WebJobs.Extensions.OpenApi.csproj
+++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/Microsoft.Azure.WebJobs.Extensions.OpenApi.csproj
@@ -32,10 +32,14 @@
-
+
+
+
+
+
diff --git a/templates/OpenApiEndpoints/OpenApiHttpTriggerContext.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiHttpTriggerContext.cs
similarity index 60%
rename from templates/OpenApiEndpoints/OpenApiHttpTriggerContext.cs
rename to src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiHttpTriggerContext.cs
index d533c40..f0f3b66 100644
--- a/templates/OpenApiEndpoints/OpenApiHttpTriggerContext.cs
+++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiHttpTriggerContext.cs
@@ -1,7 +1,10 @@
using System;
using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
using System.Reflection;
+using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
@@ -16,7 +19,7 @@ using Newtonsoft.Json.Serialization;
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
{
///
- /// This represents the context entity for .
+ /// This represents the context entity for .
///
[SuppressMessage("Design", "CA1823", Justification = "")]
[SuppressMessage("Design", "MEN002", Justification = "")]
@@ -26,17 +29,18 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
[SuppressMessage("Readability Rules", "SX1101", Justification = "")]
public class OpenApiHttpTriggerContext : IOpenApiHttpTriggerContext
{
+ private string _dllpath;
+ private Assembly _appAssembly;
+ private IOpenApiConfigurationOptions _configOptions;
+ private IOpenApiCustomUIOptions _uiOptions;
+
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
public OpenApiHttpTriggerContext()
{
- this.ApplicationAssembly = this.GetAssembly(this);
this.PackageAssembly = this.GetAssembly();
- this.OpenApiConfigurationOptions = OpenApiConfigurationResolver.Resolve(this.ApplicationAssembly);
- this.OpenApiCustomUIOptions = OpenApiCustomUIResolver.Resolve(this.ApplicationAssembly);
-
var host = HostJsonResolver.Resolve();
this.HttpSettings = host.GetHttpSettings();
@@ -49,16 +53,49 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
}
///
- public virtual Assembly ApplicationAssembly { get; }
+ public virtual Assembly ApplicationAssembly
+ {
+ get
+ {
+ if (this._appAssembly.IsNullOrDefault())
+ {
+ this._appAssembly = this.GetAssembly(this._dllpath);
+ }
+
+ return this._appAssembly;
+ }
+ }
///
public virtual Assembly PackageAssembly { get; }
///
- public virtual IOpenApiConfigurationOptions OpenApiConfigurationOptions { get; }
+ public virtual IOpenApiConfigurationOptions OpenApiConfigurationOptions
+ {
+ get
+ {
+ if (this._configOptions.IsNullOrDefault())
+ {
+ this._configOptions = OpenApiConfigurationResolver.Resolve(this.ApplicationAssembly);
+ }
+
+ return this._configOptions;
+ }
+ }
///
- public virtual IOpenApiCustomUIOptions OpenApiCustomUIOptions { get; }
+ public virtual IOpenApiCustomUIOptions OpenApiCustomUIOptions
+ {
+ get
+ {
+ if (this._uiOptions.IsNullOrDefault())
+ {
+ this._uiOptions = OpenApiCustomUIResolver.Resolve(this.ApplicationAssembly);
+ }
+
+ return this._uiOptions;
+ }
+ }
///
public virtual HttpSettings HttpSettings { get; }
@@ -72,6 +109,9 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
///
public virtual NamingStrategy NamingStrategy { get; } = new CamelCaseNamingStrategy();
+ ///
+ public virtual bool IsDevelopment { get; } = Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT") == "Development";
+
///
[Obsolete("This method is obsolete. Use GetAssembly() or GetAssembly(object) instead", error: true)]
public virtual Assembly GetExecutingAssembly()
@@ -81,6 +121,35 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
return assembly;
}
+ ///
+ public virtual IOpenApiHttpTriggerContext SetApplicationAssembly(string functionAppDirectory, bool appendBin = true)
+ {
+ if (!this._dllpath.IsNullOrWhiteSpace())
+ {
+ return this;
+ }
+
+ var file = Directory.GetFiles(functionAppDirectory, "*.deps.json", SearchOption.TopDirectoryOnly).FirstOrDefault();
+ if (file.IsNullOrWhiteSpace())
+ {
+ throw new InvalidOperationException("Invalid function app directory");
+ }
+
+ var pattern = functionAppDirectory;
+ var replacement = $"{functionAppDirectory.TrimEnd(Path.DirectorySeparatorChar)}";
+ if (appendBin)
+ {
+ replacement += $"{Path.DirectorySeparatorChar}bin";
+ }
+
+ var dllpath = file.Replace(pattern, replacement)
+ .Replace("deps.json", "dll");
+
+ this._dllpath = dllpath;
+
+ return this;
+ }
+
///
public virtual VisitorCollection GetVisitorCollection()
{
@@ -126,6 +195,24 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
return format.ToOpenApiFormat();
}
+ ///
+ public virtual AuthorizationLevel GetDocumentAuthLevel(string key = "OpenApi__AuthLevel__Document")
+ {
+ var value = Environment.GetEnvironmentVariable(key);
+ var parsed = Enum.TryParse(value, out var result) ? result : AuthorizationLevel.Anonymous;
+
+ return parsed;
+ }
+
+ ///
+ public virtual AuthorizationLevel GetUIAuthLevel(string key = "OpenApi__AuthLevel__UI")
+ {
+ var value = Environment.GetEnvironmentVariable(key);
+ var parsed = Enum.TryParse(value, out var result) ? result : AuthorizationLevel.Anonymous;
+
+ return parsed;
+ }
+
///
public virtual string GetSwaggerAuthKey(string key = "OpenApi__ApiKey")
{
@@ -153,5 +240,12 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
return assembly;
}
+
+ private Assembly GetAssembly(string dllpath)
+ {
+ var assembly = Assembly.LoadFile(dllpath);
+
+ return assembly;
+ }
}
}
diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiTriggerFunctionProvider.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiTriggerFunctionProvider.cs
new file mode 100644
index 0000000..103b254
--- /dev/null
+++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiTriggerFunctionProvider.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Reflection;
+using System.Threading.Tasks;
+
+using Microsoft.AspNetCore.Http;
+using Microsoft.Azure.WebJobs.Extensions.Http;
+using Microsoft.Azure.WebJobs.Extensions.OpenApi.Configurations;
+using Microsoft.Azure.WebJobs.Script.Description;
+
+using Newtonsoft.Json.Linq;
+
+namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
+{
+ ///
+ /// This represents the function provider entity for Open API HTTP triggers.
+ ///
+ public partial class OpenApiTriggerFunctionProvider : IFunctionProvider
+ {
+ private const string RenderSwaggerDocumentKey = "RenderSwaggerDocument";
+ private const string RenderOpenApiDocumentKey = "RenderOpenApiDocument";
+ private const string RenderSwaggerUIKey = "RenderSwaggerUI";
+ private const string RenderOAuth2RedirectKey = "RenderOAuth2Redirect";
+
+ private readonly OpenApiSettings _settings;
+ private readonly Dictionary _bindings;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public OpenApiTriggerFunctionProvider(OpenApiSettings settings)
+ {
+ this._settings = settings ?? throw new ArgumentNullException(nameof(settings));
+ this._bindings = this.SetupOpenApiHttpBindings();
+ }
+
+ ///
+ public ImmutableDictionary> FunctionErrors { get; } = new Dictionary>().ToImmutableDictionary();
+
+ ///
+ public async Task> GetFunctionMetadataAsync()
+ {
+ var functionMetadataList = this.GetFunctionMetadataList();
+
+ return await Task.FromResult(functionMetadataList.ToImmutableArray()).ConfigureAwait(false);
+ }
+
+ private Dictionary SetupOpenApiHttpBindings()
+ {
+ var renderSwaggerDocument = new HttpBindingMetadata()
+ {
+ Methods = { HttpMethods.Get },
+ Route = "swagger.{extension}",
+ AuthLevel = this._settings.AuthLevel?.Document ?? AuthorizationLevel.Anonymous,
+ };
+
+ var renderOpenApiDocument = new HttpBindingMetadata()
+ {
+ Methods = { HttpMethods.Get },
+ Route = "openapi/{version}.{extension}",
+ AuthLevel = this._settings.AuthLevel?.Document ?? AuthorizationLevel.Anonymous,
+ };
+
+ var renderOAuth2Redirect = new HttpBindingMetadata()
+ {
+ Methods = { HttpMethods.Get },
+ Route = "oauth2-redirect.html",
+ AuthLevel = this._settings.AuthLevel?.UI ?? AuthorizationLevel.Anonymous,
+ };
+
+ var bindings = new Dictionary()
+ {
+ { RenderSwaggerDocumentKey, renderSwaggerDocument },
+ { RenderOpenApiDocumentKey, renderOpenApiDocument },
+ { RenderOAuth2RedirectKey, renderOAuth2Redirect },
+ };
+
+ if (!this._settings.HideSwaggerUI)
+ {
+ var renderSwaggerUI = new HttpBindingMetadata()
+ {
+ Methods = { HttpMethods.Get },
+ Route = "swagger/ui",
+ AuthLevel = this._settings.AuthLevel?.UI ?? AuthorizationLevel.Anonymous,
+ };
+
+ bindings.Add(RenderSwaggerUIKey, renderSwaggerUI);
+ }
+
+ return bindings;
+ }
+
+ private List GetFunctionMetadataList()
+ {
+ var list = new List()
+ {
+ this.GetFunctionMetadata(RenderSwaggerDocumentKey),
+ this.GetFunctionMetadata(RenderOpenApiDocumentKey),
+ this.GetFunctionMetadata(RenderOAuth2RedirectKey),
+ };
+
+ if (!this._settings.HideSwaggerUI)
+ {
+ list.Add(this.GetFunctionMetadata(RenderSwaggerUIKey));
+ }
+
+ return list;
+ }
+
+ private FunctionMetadata GetFunctionMetadata(string functionName)
+ {
+ var assembly = Assembly.GetExecutingAssembly();
+ var functionMetadata = new FunctionMetadata()
+ {
+ Name = functionName,
+ FunctionDirectory = null,
+ ScriptFile = $"assembly:{assembly.FullName}",
+ EntryPoint = $"{assembly.GetName().Name}.{typeof(OpenApiTriggerFunctionProvider).Name}.{functionName}",
+ Language = "DotNetAssembly"
+ };
+
+ var jo = JObject.FromObject(this._bindings[functionName]);
+ var binding = BindingMetadata.Create(jo);
+ functionMetadata.Bindings.Add(binding);
+
+ return functionMetadata;
+ }
+ }
+}
diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiTriggerFunctions.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiTriggerFunctions.cs
new file mode 100644
index 0000000..97d4b05
--- /dev/null
+++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiTriggerFunctions.cs
@@ -0,0 +1,236 @@
+using System;
+using System.Net;
+using System.Threading.Tasks;
+
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
+using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
+{
+ ///
+ /// This represents the function provider entity for Open API HTTP triggers.
+ ///
+ public partial class OpenApiTriggerFunctionProvider
+ {
+ private readonly static IOpenApiHttpTriggerContext context = new OpenApiHttpTriggerContext();
+
+ ///
+ /// Invokes the HTTP trigger endpoint to get Open API document.
+ ///
+ /// instance.
+ /// File extension representing the document format. This MUST be either "json" or "yaml".
+ /// instance.
+ /// instance.
+ /// Open API document in a format of either JSON or YAML.
+ [OpenApiIgnore]
+ public static async Task RenderSwaggerDocument(HttpRequest req, string extension, ExecutionContext ctx, ILogger log)
+ {
+ log.LogInformation($"swagger.{extension} was requested.");
+
+ var result = default(string);
+ var content = default(ContentResult);
+ try
+ {
+ result = await context.SetApplicationAssembly(ctx.FunctionAppDirectory)
+ .Document
+ .InitialiseDocument()
+ .AddMetadata(context.OpenApiConfigurationOptions.Info)
+ .AddServer(req, context.HttpSettings.RoutePrefix, context.OpenApiConfigurationOptions)
+ .AddNamingStrategy(context.NamingStrategy)
+ .AddVisitors(context.GetVisitorCollection())
+ .Build(context.ApplicationAssembly)
+ .RenderAsync(context.GetOpenApiSpecVersion(context.OpenApiConfigurationOptions.OpenApiVersion), context.GetOpenApiFormat(extension))
+ .ConfigureAwait(false);
+
+ content = new ContentResult()
+ {
+ Content = result,
+ ContentType = context.GetOpenApiFormat(extension).GetContentType(),
+ StatusCode = (int)HttpStatusCode.OK,
+ };
+ }
+ catch (Exception ex)
+ {
+ log.LogError(ex.Message);
+
+ result = ex.Message;
+ if (context.IsDevelopment)
+ {
+ result += "\r\n\r\n";
+ result += ex.StackTrace;
+ }
+ content = new ContentResult()
+ {
+ Content = result,
+ ContentType = "text/plain",
+ StatusCode = (int)HttpStatusCode.InternalServerError,
+ };
+ }
+
+ return content;
+ }
+
+ ///
+ /// Invokes the HTTP trigger endpoint to get Open API document.
+ ///
+ /// instance.
+ /// Open API document spec version. This MUST be either "v2" or "v3".
+ /// File extension representing the document format. This MUST be either "json" or "yaml".
+ /// instance.
+ /// instance.
+ /// Open API document in a format of either JSON or YAML.
+ [OpenApiIgnore]
+ public static async Task RenderOpenApiDocument(HttpRequest req, string version, string extension, ExecutionContext ctx, ILogger log)
+ {
+ log.LogInformation($"{version}.{extension} was requested.");
+
+ var result = default(string);
+ var content = default(ContentResult);
+ try
+ {
+ result = await context.SetApplicationAssembly(ctx.FunctionAppDirectory)
+ .Document
+ .InitialiseDocument()
+ .AddMetadata(context.OpenApiConfigurationOptions.Info)
+ .AddServer(req, context.HttpSettings.RoutePrefix, context.OpenApiConfigurationOptions)
+ .AddNamingStrategy(context.NamingStrategy)
+ .AddVisitors(context.GetVisitorCollection())
+ .Build(context.ApplicationAssembly)
+ .RenderAsync(context.GetOpenApiSpecVersion(version), context.GetOpenApiFormat(extension))
+ .ConfigureAwait(false);
+
+ content = new ContentResult()
+ {
+ Content = result,
+ ContentType = context.GetOpenApiFormat(extension).GetContentType(),
+ StatusCode = (int)HttpStatusCode.OK,
+ };
+ }
+ catch (Exception ex)
+ {
+ log.LogError(ex.Message);
+
+ result = ex.Message;
+ if (context.IsDevelopment)
+ {
+ result += "\r\n\r\n";
+ result += ex.StackTrace;
+ }
+ content = new ContentResult()
+ {
+ Content = result,
+ ContentType = "text/plain",
+ StatusCode = (int)HttpStatusCode.InternalServerError,
+ };
+ }
+
+ return content;
+ }
+
+ ///
+ /// Invokes the HTTP trigger endpoint to render Swagger UI in HTML.
+ ///
+ /// instance.
+ /// instance.
+ /// instance.
+ /// Swagger UI in HTML.
+ [OpenApiIgnore]
+ public static async Task RenderSwaggerUI(HttpRequest req, ExecutionContext ctx, ILogger log)
+ {
+ log.LogInformation("SwaggerUI page was requested.");
+
+ var result = default(string);
+ var content = default(ContentResult);
+ try
+ {
+ result = await context.SetApplicationAssembly(ctx.FunctionAppDirectory)
+ .SwaggerUI
+ .AddMetadata(context.OpenApiConfigurationOptions.Info)
+ .AddServer(req, context.HttpSettings.RoutePrefix, context.OpenApiConfigurationOptions)
+ .BuildAsync(context.PackageAssembly, context.OpenApiCustomUIOptions)
+ .RenderAsync("swagger.json", context.GetDocumentAuthLevel(), context.GetSwaggerAuthKey())
+ .ConfigureAwait(false);
+
+ content = new ContentResult()
+ {
+ Content = result,
+ ContentType = "text/html",
+ StatusCode = (int)HttpStatusCode.OK,
+ };
+ }
+ catch (Exception ex)
+ {
+ log.LogError(ex.Message);
+
+ result = ex.Message;
+ if (context.IsDevelopment)
+ {
+ result += "\r\n\r\n";
+ result += ex.StackTrace;
+ }
+ content = new ContentResult()
+ {
+ Content = result,
+ ContentType = "text/plain",
+ StatusCode = (int)HttpStatusCode.InternalServerError,
+ };
+ }
+
+ return content;
+ }
+
+ ///
+ /// Invokes the HTTP trigger endpoint to render oauth2-redirect.html.
+ ///
+ /// instance.
+ /// instance.
+ /// instance.
+ /// oauth2-redirect.html.
+ [OpenApiIgnore]
+ public static async Task RenderOAuth2Redirect(HttpRequest req, ExecutionContext ctx, ILogger log)
+ {
+ log.LogInformation("The oauth2-redirect.html page was requested.");
+
+ var result = default(string);
+ var content = default(ContentResult);
+ try
+ {
+ result = await context.SetApplicationAssembly(ctx.FunctionAppDirectory)
+ .SwaggerUI
+ .AddServer(req, context.HttpSettings.RoutePrefix, context.OpenApiConfigurationOptions)
+ .BuildOAuth2RedirectAsync(context.PackageAssembly)
+ .RenderOAuth2RedirectAsync("oauth2-redirect.html", context.GetDocumentAuthLevel(), context.GetSwaggerAuthKey())
+ .ConfigureAwait(false);
+
+ content = new ContentResult()
+ {
+ Content = result,
+ ContentType = "text/html",
+ StatusCode = (int)HttpStatusCode.OK,
+ };
+ }
+ catch (Exception ex)
+ {
+ log.LogError(ex.Message);
+
+ result = ex.Message;
+ if (context.IsDevelopment)
+ {
+ result += "\r\n\r\n";
+ result += ex.StackTrace;
+ }
+ content = new ContentResult()
+ {
+ Content = result,
+ ContentType = "text/plain",
+ StatusCode = (int)HttpStatusCode.InternalServerError,
+ };
+ }
+
+ return content;
+ }
+ }
+}
diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiWebJobsStartup.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiWebJobsStartup.cs
new file mode 100644
index 0000000..8bb1044
--- /dev/null
+++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiWebJobsStartup.cs
@@ -0,0 +1,29 @@
+using Microsoft.Azure.WebJobs.Extensions.OpenApi;
+using Microsoft.Azure.WebJobs.Extensions.OpenApi.Configuration.AppSettings.Extensions;
+using Microsoft.Azure.WebJobs.Extensions.OpenApi.Configuration.AppSettings.Resolvers;
+using Microsoft.Azure.WebJobs.Extensions.OpenApi.Configurations;
+using Microsoft.Azure.WebJobs.Hosting;
+using Microsoft.Azure.WebJobs.Script.Description;
+using Microsoft.Extensions.DependencyInjection;
+
+[assembly: WebJobsStartup(typeof(OpenApiWebJobsStartup))]
+namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
+{
+ ///
+ /// This represents the startup entity for Open API endpoints registration
+ ///
+ public class OpenApiWebJobsStartup : IWebJobsStartup
+ {
+ private const string OpenApiSettingsKey = "OpenApi";
+
+ ///
+ public void Configure(IWebJobsBuilder builder)
+ {
+ var config = ConfigurationResolver.Resolve();
+ var settings = config.Get(OpenApiSettingsKey);
+
+ builder.Services.AddSingleton(settings);
+ builder.Services.AddSingleton();
+ }
+ }
+}
diff --git a/templates/OpenApiEndpoints/OpenApiHttpTrigger.cs b/templates/OpenApiEndpoints/OpenApiHttpTrigger.cs
deleted file mode 100644
index c8f315e..0000000
--- a/templates/OpenApiEndpoints/OpenApiHttpTrigger.cs
+++ /dev/null
@@ -1,168 +0,0 @@
-using System.Net;
-using System.Diagnostics.CodeAnalysis;
-using System.Threading.Tasks;
-
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Azure.WebJobs.Extensions.Http;
-using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
-using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;
-
-using Microsoft.Extensions.Logging;
-
-namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
-{
- ///
- /// This represents the HTTP trigger entity for OpenAPI documents.
- ///
- [SuppressMessage("Design", "CA1823", Justification = "")]
- [SuppressMessage("Design", "MEN002", Justification = "")]
- [SuppressMessage("Design", "SA1206", Justification = "")]
- [SuppressMessage("Layout Rules", "SA1311", Justification = "")]
- [SuppressMessage("Layout Rules", "SA1500", Justification = "")]
- [SuppressMessage("Readability Rules", "SX1101", Justification = "")]
- public static class OpenApiHttpTrigger
- {
- private const string V2 = "v2";
- private const string V3 = "v3";
- private const string JSON = "json";
- private const string YAML = "yaml";
-
- private readonly static IOpenApiHttpTriggerContext context = new OpenApiHttpTriggerContext();
-
- ///
- /// Invokes the HTTP trigger endpoint to get OpenAPI document.
- ///
- /// instance.
- /// File extension representing the document format. This MUST be either "json" or "yaml".
- /// instance.
- /// OpenAPI document in a format of either JSON or YAML.
- [FunctionName(nameof(OpenApiHttpTrigger.RenderSwaggerDocument))]
- [OpenApiIgnore]
- public static async Task RenderSwaggerDocument(
- [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "swagger.{extension}")] HttpRequest req,
- string extension,
- ILogger log)
- {
- log.LogInformation($"swagger.{extension} was requested.");
-
- var result = await context.Document
- .InitialiseDocument()
- .AddMetadata(context.OpenApiConfigurationOptions.Info)
- .AddServer(req, context.HttpSettings.RoutePrefix, context.OpenApiConfigurationOptions)
- .AddNamingStrategy(context.NamingStrategy)
- .AddVisitors(context.GetVisitorCollection())
- .Build(context.ApplicationAssembly)
- .RenderAsync(context.GetOpenApiSpecVersion(context.OpenApiConfigurationOptions.OpenApiVersion), context.GetOpenApiFormat(extension))
- .ConfigureAwait(false);
-
- var content = new ContentResult()
- {
- Content = result,
- ContentType = context.GetOpenApiFormat(extension).GetContentType(),
- StatusCode = (int)HttpStatusCode.OK
- };
-
- return content;
- }
-
- ///
- /// Invokes the HTTP trigger endpoint to get OpenAPI document.
- ///
- /// instance.
- /// OpenAPI document spec version. This MUST be either "v2" or "v3".
- /// File extension representing the document format. This MUST be either "json" or "yaml".
- /// instance.
- /// OpenAPI document in a format of either JSON or YAML.
- [FunctionName(nameof(OpenApiHttpTrigger.RenderOpenApiDocument))]
- [OpenApiIgnore]
- public static async Task RenderOpenApiDocument(
- [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "openapi/{version}.{extension}")] HttpRequest req,
- string version,
- string extension,
- ILogger log)
- {
- log.LogInformation($"{version}.{extension} was requested.");
-
- var result = await context.Document
- .InitialiseDocument()
- .AddMetadata(context.OpenApiConfigurationOptions.Info)
- .AddServer(req, context.HttpSettings.RoutePrefix, context.OpenApiConfigurationOptions)
- .AddNamingStrategy(context.NamingStrategy)
- .AddVisitors(context.GetVisitorCollection())
- .Build(context.ApplicationAssembly)
- .RenderAsync(context.GetOpenApiSpecVersion(version), context.GetOpenApiFormat(extension))
- .ConfigureAwait(false);
-
- var content = new ContentResult()
- {
- Content = result,
- ContentType = context.GetOpenApiFormat(extension).GetContentType(),
- StatusCode = (int)HttpStatusCode.OK
- };
-
- return content;
- }
-
- ///
- /// Invokes the HTTP trigger endpoint to render Swagger UI in HTML.
- ///
- /// instance.
- /// instance.
- /// Swagger UI in HTML.
- [FunctionName(nameof(OpenApiHttpTrigger.RenderSwaggerUI))]
- [OpenApiIgnore]
- public static async Task RenderSwaggerUI(
- [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "swagger/ui")] HttpRequest req,
- ILogger log)
- {
- log.LogInformation("SwaggerUI page was requested.");
-
- var result = await context.SwaggerUI
- .AddMetadata(context.OpenApiConfigurationOptions.Info)
- .AddServer(req, context.HttpSettings.RoutePrefix, context.OpenApiConfigurationOptions)
- .BuildAsync(context.PackageAssembly, context.OpenApiCustomUIOptions)
- .RenderAsync("swagger.json", context.GetSwaggerAuthKey())
- .ConfigureAwait(false);
-
- var content = new ContentResult()
- {
- Content = result,
- ContentType = "text/html",
- StatusCode = (int)HttpStatusCode.OK
- };
-
- return content;
- }
-
- ///
- /// Invokes the HTTP trigger endpoint to render oauth2-redirect.html.
- ///
- /// instance.
- /// instance.
- /// oauth2-redirect.html.
- [FunctionName(nameof(OpenApiHttpTrigger.RenderOAuth2Redirect))]
- [OpenApiIgnore]
- public static async Task RenderOAuth2Redirect(
- [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "oauth2-redirect.html")] HttpRequest req,
- ILogger log)
- {
- log.LogInformation("The oauth2-redirect.html page was requested.");
-
- var result = await context.SwaggerUI
- .AddServer(req, context.HttpSettings.RoutePrefix, context.OpenApiConfigurationOptions)
- .BuildOAuth2RedirectAsync(context.PackageAssembly)
- .RenderOAuth2RedirectAsync("oauth2-redirect.html", context.GetSwaggerAuthKey())
- .ConfigureAwait(false);
-
- var content = new ContentResult()
- {
- Content = result,
- ContentType = "text/html",
- StatusCode = (int)HttpStatusCode.OK
- };
-
- return content;
- }
- }
-}
diff --git a/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Extensions/SwaggerUIExtensionsTests.cs b/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Extensions/SwaggerUIExtensionsTests.cs
index 577c882..6186e82 100644
--- a/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Extensions/SwaggerUIExtensionsTests.cs
+++ b/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Extensions/SwaggerUIExtensionsTests.cs
@@ -1,11 +1,11 @@
using System;
using System.Threading.Tasks;
-using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
-using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;
-
using FluentAssertions;
+using Microsoft.Azure.WebJobs.Extensions.Http;
+using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
+using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
@@ -35,7 +35,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests.Extensions
var rendered = "hello world";
var ui = new Mock();
- ui.Setup(p => p.RenderAsync(It.IsAny(), It.IsAny())).ReturnsAsync(rendered);
+ ui.Setup(p => p.RenderAsync(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(rendered);
var task = Task.FromResult(ui.Object);
@@ -64,7 +64,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests.Extensions
var rendered = "hello world";
var ui = new Mock();
- ui.Setup(p => p.RenderOAuth2RedirectAsync(It.IsAny(), It.IsAny())).ReturnsAsync(rendered);
+ ui.Setup(p => p.RenderOAuth2RedirectAsync(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(rendered);
var task = Task.FromResult(ui.Object);
diff --git a/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests.csproj b/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests.csproj
index 2e25f86..30e6f83 100644
--- a/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests.csproj
+++ b/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests.csproj
@@ -36,10 +36,4 @@
-
-
-
-
-
-
diff --git a/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/OpenApiHttpTriggerContextTests.cs b/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/OpenApiHttpTriggerContextTests.cs
index e680c20..c0ac17b 100644
--- a/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/OpenApiHttpTriggerContextTests.cs
+++ b/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/OpenApiHttpTriggerContextTests.cs
@@ -1,3 +1,6 @@
+using System;
+using System.IO;
+using System.Linq;
using System.Reflection;
using FluentAssertions;
@@ -11,25 +14,47 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests
[TestClass]
public class OpenApiHttpTriggerContextTests
{
- [TestMethod]
- public void Given_Type_When_Initiated_Then_It_Should_Return_ApplicationAssembly()
+ [DataTestMethod]
+ [DataRow(typeof(OpenApiHttpTriggerContextTests))]
+ public void Given_Type_When_Initiated_Then_It_Should_Return_ApplicationAssemblyWithGivenType(Type type)
{
+ var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
- var assembly = context.ApplicationAssembly;
+ var assembly = context.SetApplicationAssembly(location, false)
+ .ApplicationAssembly;
- assembly.DefinedTypes.Should().Contain(typeof(IOpenApiHttpTriggerContext).GetTypeInfo());
- assembly.DefinedTypes.Should().Contain(typeof(OpenApiHttpTriggerContext).GetTypeInfo());
- assembly.DefinedTypes.Should().Contain(typeof(OpenApiHttpTrigger).GetTypeInfo());
- assembly.DefinedTypes.Should().NotContain(typeof(ISwaggerUI).GetTypeInfo());
+ var ti = type.GetTypeInfo();
+
+ assembly.DefinedTypes.Select(p => p.FullName).Should().Contain(ti.FullName);
+ }
+
+ [DataTestMethod]
+ [DataRow(typeof(IOpenApiHttpTriggerContext))]
+ [DataRow(typeof(OpenApiHttpTriggerContext))]
+ [DataRow(typeof(OpenApiTriggerFunctionProvider))]
+ [DataRow(typeof(ISwaggerUI))]
+ public void Given_Type_When_Initiated_Then_It_Should_NotReturn_ApplicationAssemblyWithGivenType(Type type)
+ {
+ var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
+ var context = new OpenApiHttpTriggerContext();
+
+ var assembly = context.SetApplicationAssembly(location, false)
+ .ApplicationAssembly;
+
+ var ti = type.GetTypeInfo();
+
+ assembly.DefinedTypes.Select(p => p.FullName).Should().NotContain(ti.FullName);
}
[TestMethod]
public void Given_Type_When_Initiated_Then_It_Should_Return_PackageAssembly()
{
+ var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
- var assembly = context.PackageAssembly;
+ var assembly = context.SetApplicationAssembly(location, false)
+ .PackageAssembly;
assembly.DefinedTypes.Should().Contain(typeof(ISwaggerUI).GetTypeInfo());
assembly.DefinedTypes.Should().NotContain(typeof(IOpenApiHttpTriggerContext).GetTypeInfo());
@@ -38,9 +63,11 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests
[TestMethod]
public void Given_Type_When_Initiated_Then_It_Should_Return_OpenApiConfigurationOptions()
{
+ var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
- var options = context.OpenApiConfigurationOptions;
+ var options = context.SetApplicationAssembly(location, false)
+ .OpenApiConfigurationOptions;
options.Info.Version.Should().Be("1.0.0");
options.Servers.Count.Should().Be(0);
@@ -49,9 +76,11 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests
[TestMethod]
public void Given_Type_When_Initiated_Then_It_Should_Return_OpenApiCustomUIOptions()
{
+ var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
- var options = context.OpenApiCustomUIOptions;
+ var options = context.SetApplicationAssembly(location, false)
+ .OpenApiCustomUIOptions;
options.CustomStylesheetPath.Should().Be("dist.custom.css");
options.CustomJavaScriptPath.Should().Be("dist.custom.js");
@@ -60,9 +89,11 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests
[TestMethod]
public void Given_Type_When_Initiated_Then_It_Should_Return_HttpSettings()
{
+ var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
- var settings = context.HttpSettings;
+ var settings = context.SetApplicationAssembly(location, false)
+ .HttpSettings;
settings.RoutePrefix.Should().Be("api");
@@ -73,9 +104,11 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests
[DataRow("v3", OpenApiSpecVersion.OpenApi3_0)]
public void Given_Type_When_GetOpenApiSpecVersion_Invoked_Then_It_Should_Return_Result(string version, OpenApiSpecVersion expected)
{
+ var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
- var result = context.GetOpenApiSpecVersion(version);
+ var result = context.SetApplicationAssembly(location, false)
+ .GetOpenApiSpecVersion(version);
result.Should().Be(expected);
}
@@ -85,9 +118,11 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests
[DataRow("json", OpenApiFormat.Json)]
public void Given_Type_When_GetOpenApiSpecVersion_Invoked_Then_It_Should_Return_Result(string format, OpenApiFormat expected)
{
+ var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
- var result = context.GetOpenApiFormat(format);
+ var result = context.SetApplicationAssembly(location, false)
+ .GetOpenApiFormat(format);
result.Should().Be(expected);
}
diff --git a/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/OpenApiTriggerFunctionProviderTests.cs b/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/OpenApiTriggerFunctionProviderTests.cs
new file mode 100644
index 0000000..c4855f8
--- /dev/null
+++ b/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/OpenApiTriggerFunctionProviderTests.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+
+using FluentAssertions;
+
+using Microsoft.Azure.WebJobs.Extensions.Http;
+using Microsoft.Azure.WebJobs.Extensions.OpenApi.Configurations;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using Moq;
+
+namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests
+{
+ [TestClass]
+ public class OpenApiTriggerFunctionProviderTests
+ {
+ [TestMethod]
+ public void Given_Null_When_Instantiated_Then_It_Should_Throw_Exception()
+ {
+ Action action = () => new OpenApiTriggerFunctionProvider(null);
+
+ action.Should().Throw();
+ }
+
+ [DataTestMethod]
+ [DataRow(true, 3)]
+ [DataRow(false, 4)]
+ public async Task Given_HideSwaggerUI_When_GetFunctionMetadataAsync_Invoked_Then_It_Should_Return_Result(bool hideSwaggerUI, int expected)
+ {
+ var settings = new Mock();
+ settings.SetupGet(p => p.HideSwaggerUI).Returns(hideSwaggerUI);
+
+ var provider = new OpenApiTriggerFunctionProvider(settings.Object);
+
+ var result = await provider.GetFunctionMetadataAsync().ConfigureAwait(false);
+
+ result.Should().HaveCount(expected);
+ }
+
+ [DataTestMethod]
+ [DataRow(AuthorizationLevel.Anonymous, AuthorizationLevel.Anonymous)]
+ [DataRow(AuthorizationLevel.Anonymous, AuthorizationLevel.Function)]
+ [DataRow(AuthorizationLevel.Function, AuthorizationLevel.Anonymous)]
+ [DataRow(AuthorizationLevel.Function, AuthorizationLevel.Function)]
+ public async Task Given_AuthLevel_When_GetFunctionMetadataAsync_Invoked_Then_It_Should_Return_Result(AuthorizationLevel authLevelDoc, AuthorizationLevel authLevelUI)
+ {
+ var authLevelSettings = new Mock();
+ authLevelSettings.SetupGet(p => p.Document).Returns(authLevelDoc);
+ authLevelSettings.SetupGet(p => p.UI).Returns(authLevelUI);
+
+ var settings = new Mock();
+ settings.SetupGet(p => p.HideSwaggerUI).Returns(false);
+ settings.SetupGet(p => p.AuthLevel).Returns(authLevelSettings.Object);
+
+ var provider = new OpenApiTriggerFunctionProvider(settings.Object);
+
+ var result = await provider.GetFunctionMetadataAsync().ConfigureAwait(false);
+
+ result.Single(p => p.Name == "RenderSwaggerDocument").Bindings.First().Raw.Value("authLevel").Should().Be((int)authLevelDoc);
+ result.Single(p => p.Name == "RenderOpenApiDocument").Bindings.First().Raw.Value("authLevel").Should().Be((int)authLevelDoc);
+ result.Single(p => p.Name == "RenderSwaggerUI").Bindings.First().Raw.Value("authLevel").Should().Be((int)authLevelUI);
+ result.Single(p => p.Name == "RenderOAuth2Redirect").Bindings.First().Raw.Value("authLevel").Should().Be((int)authLevelUI);
+ }
+ }
+}