Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using CseApi.Functions.Shared;
using CseApi.Helpers.Config;
using CseApi.Helpers.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace CseApi.Functions.Swagger
{
public static class Swagger
{
private static IServiceProviderHelper _serviceProviderHelper = new ServiceProviderHelper(ServiceProviderShared.ServiceProvider);
private const string _functionName = "Swagger";
private const string _swaggerRoute = "swagger/{fileName?}";
private const string _githubSwaggerUrl = "https://raw.githubusercontent.com/swagger-api/swagger-ui/master/dist";
private const string _openApiJsonPath = @"Functions\Swagger\openapi.json";
private const string _localBasePath = "/api";
private const string _stagingPartialHost = "staging.azurewebsites.net";
private const string _stagingBasePath = "/staging/api/v1";
private const string _prodPartialHost = "prod.azurewebsites.net";
private const string _prodBasePath = "/prod/api/v1";
private static Regex _fileExtensionRegex = new Regex("\\.(?<extension>(css|js|html|png|map))$");
private static byte[] _indexHtml = null;
private static byte[] _openApiJson = null;
private static readonly Dictionary<string, string> _mimeMapping = new Dictionary<string, string>
{
{ "js", "application/javascript" },
{ "json", "application/json" },
{ "map", "application/javascript" },
{ "css", "text/css" },
{ "png", "image/png" },
{ "html", "text/html" }
};
private static string GetBaseUrl()
{
var openApiHost = ConfigurationHelper.Config["OpenApiHost"];
var openApiBasePath = ConfigurationHelper.Config["OpenApiBasePath"];
var openApiScheme = ConfigurationHelper.Config["OpenApiScheme"];
var baseUrl = $"{openApiScheme}://{openApiHost}{openApiBasePath}";
return baseUrl;
}
// Loads the openapi.json from the fs and replaces it's contents based on the current context.
private static byte[] GetOpenApiJson(string functionAppDirectory)
{
if (_openApiJson == null || _openApiJson.Length == 0)
{
string json = File.ReadAllText($@"{functionAppDirectory}\{_openApiJsonPath}");
dynamic jsonObj = JsonConvert.DeserializeObject(json);
jsonObj["host"] = ConfigurationHelper.Config["OpenApiHost"];
jsonObj["basePath"] = ConfigurationHelper.Config["OpenApiBasePath"];
jsonObj["schemes"] = new JArray() { ConfigurationHelper.Config["OpenApiScheme"] };
string output = JsonConvert.SerializeObject(jsonObj, Formatting.Indented);
_openApiJson = Encoding.UTF8.GetBytes(output);
}
return _openApiJson;
}
// Gets the swagger ui index.html from github and repalces the url and add the oauth redirect url
private async static Task<byte[]> GetIndex()
{
if (_indexHtml == null || _indexHtml.Length == 0)
{
var request = _serviceProviderHelper.GetHttpHandler().CreateGetRequest($"{_githubSwaggerUrl}/index.html");
var response = await _serviceProviderHelper.GetHttpHandler().SendAsync(request);
var contents = await response.Content.ReadAsStringAsync();
var stringToReplace = @"url: ""https://petstore.swagger.io/v2/swagger.json""";
var url = $@"url: '{GetBaseUrl()}/swagger/openapi.json',";
var oauth2RedirectUrl = $@"oauth2RedirectUrl: '{GetBaseUrl()}/swagger/oauth2-redirect.html'";
contents = contents.Replace(stringToReplace, $@"{url} {oauth2RedirectUrl}");
_indexHtml = Encoding.UTF8.GetBytes(contents);
}
return _indexHtml;
}
private static string GetMimeType(string fileName)
{
var fileExtensionMatch = _fileExtensionRegex.Match(fileName);
var fileExtension = fileExtensionMatch.Success ? fileExtensionMatch.Groups["extension"].Value : null;
return fileExtension != null ? _mimeMapping[fileExtension] : null;
}
[FunctionName(_functionName)]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = _swaggerRoute)] HttpRequest req,
string fileName,
ExecutionContext context,
ILogger log)
{
log.LogInformation($"[{_functionName}] started execution from host: {req.Host.Value}");
try
{
if (req.Path.Value.EndsWith("/swagger"))
{
return new RedirectResult(req.GetEncodedUrl() + "/");
}
_serviceProviderHelper.SetUpLogger(log);
var httpHandler = _serviceProviderHelper.GetHttpHandler();
// When requesting /api/swagger serve up the index
if (string.IsNullOrEmpty(fileName))
{
fileName = "index.html";
}
// Intercept index.html and replace contents
if (fileName == "index.html")
{
return new FileContentResult(await GetIndex(), "text/html");
}
// Intercept openapi.json and replace contents and load from filesystem.
if (fileName == "openapi.json")
{
return new FileContentResult(GetOpenApiJson(context.FunctionAppDirectory), "text/html");
}
// For any other calls pipe the response from github (css, js, ect..)
else
{
var request = httpHandler.CreateGetRequest($"{_githubSwaggerUrl}/{fileName}");
var mimeType = GetMimeType(fileName);
if (mimeType == null)
{
log.LogWarning($"Could not resolve mime type with filename: {fileName}");
}
var response = await httpHandler.SendAsync(request);
var outputStream = await response.Content.ReadAsStreamAsync();
return new FileStreamResult(outputStream, mimeType ?? response.Content.Headers.ContentType.MediaType);
}
}
catch (Exception e)
{
log.LogError(e.ToString());
return new InternalServerErrorObjectResult($"Error serving swagger: {e.Message}");
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.