Created
January 18, 2019 17:51
-
-
Save engineersamuel/f3ab0174a8e3886fbe16b14efad2eb00 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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