private void CreateSecuritySchemes(OpenApiDocument openApiDocument, OpenApiConfiguration configuration) { foreach (KeyValuePair <string, OpenApiSecurityScheme> keyValuePair in configuration.SecuritySchemes) { // SecurityScheme if (openApiDocument.Components.SecuritySchemes == null) { openApiDocument.Components.SecuritySchemes = new Dictionary <string, OpenApiSecurityScheme>(); } openApiDocument.Components.SecuritySchemes.Add(keyValuePair.Key, keyValuePair.Value); // SecurityRequirement if (openApiDocument.SecurityRequirements == null) { openApiDocument.SecurityRequirements = new List <OpenApiSecurityRequirement>(); } openApiDocument.SecurityRequirements.Add(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = keyValuePair.Key, Type = ReferenceType.SecurityScheme } }, new List <string>() } }); } }
public void Compile(IReadOnlyCollection <AbstractFunctionDefinition> functionDefinitions, OpenApiConfiguration openApiConfiguration, OpenApiOutputModel openApiOutputModel, string outputBinaryFolder) { HandlebarsHelperRegistration.RegisterHelpers(); HttpFunctionDefinition[] httpFunctionDefinitions = functionDefinitions .OfType <HttpFunctionDefinition>() .Where(x => !string.IsNullOrWhiteSpace(x.Route)) .ToArray(); if (!httpFunctionDefinitions.Any()) { return; } List <object> proxyDefinitions = new List <object>(httpFunctionDefinitions); var isYamlOutput = openApiConfiguration.ApiOutputFormat == ApiOutputFormat.Yaml; if (openApiConfiguration.IsOpenApiOutputEnabled) { proxyDefinitions.Add(new { Name = "OpenApiDefinitionRoute", Route = "/openapi." + (isYamlOutput ? "yaml" : "json"), IsOpenApiYaml = isYamlOutput, IsOpenApiJson = !isYamlOutput }); Debug.Assert(openApiOutputModel != null); if (openApiOutputModel.IsConfiguredForUserInterface) { proxyDefinitions.Add(new { Name = "OpenApiProvider", Route = openApiConfiguration.UserInterfaceRoute + "/{name}", IsOpenApiUi = true }); } } string templateSource = _templateProvider.GetProxiesJsonTemplate(); Func <object, string> template = Handlebars.Compile(templateSource); string json = template(proxyDefinitions); DirectoryInfo folder = Directory.CreateDirectory(Path.Combine(outputBinaryFolder, "..")); string filename = Path.Combine(folder.FullName, "proxies.json"); using (Stream stream = new FileStream(filename, FileMode.Create)) using (StreamWriter writer = new StreamWriter(stream)) { writer.Write(json); } }
public OpenApiCompilerConfiguration(OpenApiConfiguration configuration) { foreach (var documentFilterFactory in configuration.DocumentFilterFactories) { DocumentFilters.Add(documentFilterFactory()); } foreach (var operationFilterFactory in configuration.OperationFilterFactories) { OperationFilters.Add(operationFilterFactory()); } foreach (var parameterFilterFactory in configuration.ParameterFilterFactories) { ParameterFilters.Add(parameterFilterFactory()); } foreach (var schemaFilterFactory in configuration.SchemaFilterFactories) { SchemaFilters.Add(schemaFilterFactory()); } foreach (var xmlDocFactory in configuration.XmlDocFactories) { SchemaFilters.Add(new OpenApiXmlCommentsSchemaFilter(xmlDocFactory())); } SchemaIdSelector = configuration.SchemaIdSelector; if (SchemaIdSelector == null) { SchemaIdSelector = type => { var typeName = type.GetAttributeValue((DataContractAttribute attribute) => attribute.Name) ?? type.FriendlyId(); return(typeName.SanitizeClassName()); }; } }
public OpenApiOutputModel Compile(OpenApiConfiguration configuration, IReadOnlyCollection <AbstractFunctionDefinition> abstractFunctionDefinitions, string outputBinaryFolder) { string apiPrefix = GetApiPrefix(outputBinaryFolder); if (!configuration.IsValid) { throw new ConfigurationException("Open API implementation is partially complete, a title and a version must be specified"); } if (!configuration.IsOpenApiOutputEnabled) { return(null); } HttpFunctionDefinition[] functionDefinitions = abstractFunctionDefinitions.OfType <HttpFunctionDefinition>().ToArray(); if (functionDefinitions.Length == 0) { return(null); } OpenApiDocument openApiDocument = new OpenApiDocument { Info = new OpenApiInfo { Version = configuration.Version, Title = configuration.Title }, Servers = configuration.Servers?.Select(x => new OpenApiServer { Url = x }).ToArray(), Paths = new OpenApiPaths(), Components = new OpenApiComponents { Schemas = new Dictionary <string, OpenApiSchema>() } }; SchemaReferenceRegistry registry = new SchemaReferenceRegistry(); CreateTags(functionDefinitions, openApiDocument); CreateSchemas(functionDefinitions, openApiDocument, registry); CreateOperationsFromRoutes(functionDefinitions, openApiDocument, registry, apiPrefix); if (openApiDocument.Paths.Count == 0) { return(null); } string yaml = openApiDocument.Serialize(OpenApiSpecVersion.OpenApi3_0, OpenApiFormat.Yaml); OpenApiOutputModel result = new OpenApiOutputModel { OpenApiSpecification = new OpenApiFileReference { Content = yaml, Filename = "openapi.yaml" } }; if (!string.IsNullOrWhiteSpace(configuration.UserInterfaceRoute)) { result.SwaggerUserInterface = CopySwaggerUserInterfaceFilesToWebFolder(); } return(result); }
private void CopyReDocUserInterfaceFilesToWebFolder(OpenApiConfiguration configuration, IList <OpenApiFileReference> openApiFileReferences) { var route = $"{configuration.ReDocUserInterfaceRoute ?? "redoc"}"; // StyleSheets StringBuilder links = new StringBuilder(""); foreach (var injectedStylesheet in configuration.ReDocInjectedStylesheets) { var resourceAssemblyName = injectedStylesheet.resourceAssembly.GetName().Name; var styleSheetName = $"{resourceAssemblyName}.{injectedStylesheet.resourceName}"; var content = LoadResourceFromAssembly(injectedStylesheet.resourceAssembly, styleSheetName); var filename = styleSheetName.Substring(resourceAssemblyName.Length + 1); links.Append($"{Environment.NewLine} <link rel='stylesheet' type='text/css' href='/{route}/{filename}' media='{injectedStylesheet.media}' />"); openApiFileReferences.Add(new OpenApiFileReference { Content = content, Filename = $"ReDoc.{filename}" }); } links.Append($"{Environment.NewLine}</head>"); // Resources foreach (var injectedResource in configuration.ReDocInjectedResources) { var resourceAssemblyName = injectedResource.resourceAssembly.GetName().Name; var resourceName = $"{resourceAssemblyName}.{injectedResource.resourceName}"; var content = LoadResourceFromAssembly(injectedResource.resourceAssembly, resourceName); var filename = resourceName.Substring(resourceAssemblyName.Length + 1); openApiFileReferences.Add(new OpenApiFileReference { Content = content, Filename = $"ReDoc.{filename}" }); } // Logo if (configuration.ReDocInjectedLogo != default(ValueTuple <Assembly, string>)) { var resourceAssemblyName = configuration.InjectedLogo.resourceAssembly.GetName().Name; var resourceName = $"{resourceAssemblyName}.{configuration.InjectedLogo.resourceName}"; var content = LoadResourceFromAssembly(configuration.InjectedLogo.resourceAssembly, resourceName); var filename = resourceName.Substring(resourceAssemblyName.Length + 1); var extension = Path.GetExtension(filename); openApiFileReferences.Add(new OpenApiFileReference { Content = content, Filename = $"ReDoc.logo{extension}" }); } // Scripts StringBuilder scripts = new StringBuilder(); foreach (var injectedJavaScript in configuration.ReDocInjectedJavaScripts) { var resourceAssemblyName = injectedJavaScript.resourceAssembly.GetName().Name; var javaScriptName = $"{resourceAssemblyName}.{injectedJavaScript.resourceName}"; var content = LoadResourceFromAssembly(injectedJavaScript.resourceAssembly, javaScriptName); var filename = javaScriptName.Substring(resourceAssemblyName.Length + 1); scripts.Append($" <script src=\"/{route}/{filename}\" > </script>{ Environment.NewLine}"); openApiFileReferences.Add(new OpenApiFileReference { Content = content, Filename = $"ReDoc.{filename}" }); } // Additional necessary scripts var necessaryScripts = new List <string>(); necessaryScripts.Add("Resources.ReDoc.topbar-multiple-specs.js"); foreach (var resourceName in necessaryScripts) { var resourceAssemblyName = Assembly.GetExecutingAssembly().GetName().Name; var javaScriptName = $"{resourceAssemblyName}.{resourceName}"; var content = LoadResourceFromAssembly(Assembly.GetExecutingAssembly(), javaScriptName); var filename = javaScriptName.Substring(resourceAssemblyName.Length + 1); scripts.Append($" <script src=\"/{route}/{filename.Replace("Resources.ReDoc.", "")}\" > </script>{ Environment.NewLine}"); openApiFileReferences.Add(new OpenApiFileReference { Content = content, Filename = filename.Replace("Resources.ReDoc.", "ReDoc.") }); } scripts.Append("</body>"); // Other necessary files const string prefix = "Resources.ReDoc."; var necessaryFiles = new List <string>(); necessaryFiles.Add("Resources.ReDoc.favicon-16x16.ico"); necessaryFiles.Add("Resources.ReDoc.favicon-32x32.ico"); necessaryFiles.Add("Resources.ReDoc.index.html"); necessaryFiles.Add("Resources.ReDoc.redoc-logo.png"); foreach (var resourceName in necessaryFiles) { var resourceAssemblyName = Assembly.GetExecutingAssembly().GetName().Name; var reDocFileName = $"{resourceAssemblyName}.{resourceName}"; var content = LoadResourceFromAssembly(Assembly.GetExecutingAssembly(), reDocFileName); var filename = reDocFileName.Substring(resourceAssemblyName.Length + 1); if (filename.EndsWith("index.html")) { var documentInfo = configuration.OpenApiDocumentInfos .Where(x => x.Value.Selected) .Select(x => x.Value) .DefaultIfEmpty(configuration.OpenApiDocumentInfos.FirstOrDefault().Value) .First(); var contentString = Encoding.UTF8.GetString(content); contentString = contentString.Replace("/redoc/openapi.yaml", $"/{route}/{documentInfo.DocumentRoute}"); contentString = contentString.Replace("</head>", links.ToString()); contentString = contentString.Replace("</body>", scripts.ToString()); content = Encoding.UTF8.GetBytes(contentString); } openApiFileReferences.Add(new OpenApiFileReference { Content = content, Filename = $"ReDoc.{filename.Substring(prefix.Length)}" }); } }
public OpenApiOutputModel Compile(OpenApiConfiguration configuration, IReadOnlyCollection <AbstractFunctionDefinition> abstractFunctionDefinitions, string outputBinaryFolder) { if (configuration == null) { return(null); } string apiPrefix = GetApiPrefix(outputBinaryFolder); if (!configuration.IsValid) { throw new ConfigurationException("Open API implementation is partially complete, a title and a version must be specified"); } if (!configuration.IsOpenApiOutputEnabled) { return(null); } var functionDefinitions = abstractFunctionDefinitions.OfType <HttpFunctionDefinition>().ToList(); if (functionDefinitions.Count() == 0) { return(null); } IDictionary <string, OpenApiDocumentsSpec> openApiDocumentsSpec = new Dictionary <string, OpenApiDocumentsSpec>(); IDictionary <string, OpenApiDocumentsSpec> reDocDocumentsSpec = new Dictionary <string, OpenApiDocumentsSpec>(); OpenApiOutputModel outputModel = new OpenApiOutputModel(); foreach (var keyValuePair in configuration.OpenApiDocumentInfos) { OpenApiDocument openApiDocument = new OpenApiDocument { Info = keyValuePair.Value.OpenApiInfo, Servers = configuration.Servers?.Select(x => new OpenApiServer { Url = x }).ToArray(), Paths = new OpenApiPaths(), Components = new OpenApiComponents { Schemas = new Dictionary <string, OpenApiSchema>(), } }; var functionFilter = keyValuePair.Value.HttpFunctionFilter; if (functionFilter == null) { functionFilter = new OpenApiHttpFunctionFilterDummy(); } var compilerConfiguration = new OpenApiCompilerConfiguration(configuration); SchemaReferenceRegistry registry = new SchemaReferenceRegistry(compilerConfiguration); CreateTags(functionDefinitions, functionFilter, openApiDocument); CreateSchemas(functionDefinitions, functionFilter, openApiDocument, registry); CreateOperationsFromRoutes(functionDefinitions, functionFilter, openApiDocument, registry, apiPrefix, compilerConfiguration); CreateSecuritySchemes(openApiDocument, configuration); FilterDocument(compilerConfiguration.DocumentFilters, openApiDocument, keyValuePair.Value.DocumentRoute); if (openApiDocument.Paths.Count == 0) { continue; } // TODO: FIXME: // Hack: Empty OpenApiSecurityRequirement lists are not serialized by the standard Microsoft // implementation. Therefore we add a null object to the list and fix it here by hand. var yaml = openApiDocument.Serialize(OpenApiSpecVersion.OpenApi3_0, OpenApiFormat.Yaml); yaml = Regex.Replace(yaml, $"security:\n.*?- \n", "security: []\n"); outputModel.OpenApiFileReferences.Add( new OpenApiFileReference { Filename = $"OpenApi.{keyValuePair.Value.DocumentRoute.Replace('/', '.')}", Content = Encoding.UTF8.GetBytes(yaml) } ); openApiDocumentsSpec.Add(openApiDocument.Info.Title, new OpenApiDocumentsSpec { Title = keyValuePair.Value.OpenApiInfo.Title, Selected = keyValuePair.Value.Selected, Path = $"/{configuration.UserInterfaceRoute ?? "openapi"}/{keyValuePair.Value.DocumentRoute}" }); // Create reDoc YAML if (!string.IsNullOrWhiteSpace(configuration.ReDocUserInterfaceRoute)) { FilterDocument(compilerConfiguration.ReDocDocumentFilters, openApiDocument, keyValuePair.Value.DocumentRoute); // TODO: FIXME: // Hack: Empty OpenApiSecurityRequirement lists are not serialized by the standard Microsoft // implementation. Therefore we add a null object to the list and fix it here by hand. var reDocYaml = openApiDocument.Serialize(OpenApiSpecVersion.OpenApi3_0, OpenApiFormat.Yaml); reDocYaml = Regex.Replace(reDocYaml, $"security:\n.*?- \n", "security: []\n"); outputModel.OpenApiFileReferences.Add( new OpenApiFileReference { Filename = $"ReDoc.{keyValuePair.Value.DocumentRoute.Replace('/', '.')}", Content = Encoding.UTF8.GetBytes(reDocYaml) } ); reDocDocumentsSpec.Add(openApiDocument.Info.Title, new OpenApiDocumentsSpec { Title = keyValuePair.Value.OpenApiInfo.Title, Selected = keyValuePair.Value.Selected, Path = $"/{configuration.ReDocUserInterfaceRoute ?? "redoc"}/{keyValuePair.Value.DocumentRoute}" }); } } if (!string.IsNullOrWhiteSpace(configuration.UserInterfaceRoute)) { outputModel.OpenApiFileReferences.Add( new OpenApiFileReference { Filename = "OpenApi.openapi-documents-spec.json", Content = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(openApiDocumentsSpec.Values.ToArray())) } ); CopySwaggerUserInterfaceFilesToWebFolder(configuration, outputModel.OpenApiFileReferences); } if (!string.IsNullOrWhiteSpace(configuration.ReDocUserInterfaceRoute)) { outputModel.OpenApiFileReferences.Add( new OpenApiFileReference { Filename = "ReDoc.redoc-documents-spec.json", Content = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(reDocDocumentsSpec.Values.ToArray())) } ); CopyReDocUserInterfaceFilesToWebFolder(configuration, outputModel.OpenApiFileReferences); } outputModel.UserInterfaceRoute = configuration.UserInterfaceRoute; outputModel.ReDocUserInterfaceRoute = configuration.ReDocUserInterfaceRoute; return(outputModel); }
private void CopySwaggerUserInterfaceFilesToWebFolder(OpenApiConfiguration configuration, IList <OpenApiFileReference> openApiFileReferences) { var route = $"{configuration.UserInterfaceRoute ?? "openapi"}"; // StyleSheets StringBuilder links = new StringBuilder(""); foreach (var injectedStylesheet in configuration.InjectedStylesheets) { var resourceAssemblyName = injectedStylesheet.resourceAssembly.GetName().Name; var styleSheetName = $"{resourceAssemblyName}.{injectedStylesheet.resourceName}"; var content = LoadResourceFromAssembly(injectedStylesheet.resourceAssembly, styleSheetName); var filename = styleSheetName.Substring(resourceAssemblyName.Length + 1); links.Append($"{Environment.NewLine} <link rel='stylesheet' type='text/css' href='/{route}/{filename}' media='{injectedStylesheet.media}' />"); openApiFileReferences.Add(new OpenApiFileReference { Content = content, Filename = $"OpenApi.{filename}" }); } links.Append($"{Environment.NewLine} </head>"); // Resources foreach (var injectedResource in configuration.InjectedResources) { var resourceAssemblyName = injectedResource.resourceAssembly.GetName().Name; var resourceName = $"{resourceAssemblyName}.{injectedResource.resourceName}"; var content = LoadResourceFromAssembly(injectedResource.resourceAssembly, resourceName); var filename = resourceName.Substring(resourceAssemblyName.Length + 1); openApiFileReferences.Add(new OpenApiFileReference { Content = content, Filename = $"OpenApi.{filename}" }); } // Logos if ((configuration.InjectedLogo) != default(ValueTuple <Assembly, string>)) { var resourceAssemblyName = configuration.InjectedLogo.resourceAssembly.GetName().Name; var resourceName = $"{resourceAssemblyName}.{configuration.InjectedLogo.resourceName}"; var content = LoadResourceFromAssembly(configuration.InjectedLogo.resourceAssembly, resourceName); var filename = resourceName.Substring(resourceAssemblyName.Length + 1); var extension = Path.GetExtension(filename); openApiFileReferences.Add(new OpenApiFileReference { Content = content, Filename = $"OpenApi.logo{extension}" }); } // Scripts StringBuilder scripts = new StringBuilder(); foreach (var injectedJavaScript in configuration.InjectedJavaScripts) { var resourceAssemblyName = injectedJavaScript.resourceAssembly.GetName().Name; var javaScriptName = $"{resourceAssemblyName}.{injectedJavaScript.resourceName}"; var content = LoadResourceFromAssembly(injectedJavaScript.resourceAssembly, javaScriptName); var filename = javaScriptName.Substring(resourceAssemblyName.Length + 1); scripts.Append($" <script src=\"/{route}/{filename}\" > </script>{ Environment.NewLine}"); openApiFileReferences.Add(new OpenApiFileReference { Content = content, Filename = $"OpenApi.{filename}" }); } // Additional necessary scripts var necessaryScripts = new List <string>(); necessaryScripts.Add("Resources.OpenApi.topbar-multiple-specs.js"); foreach (var resourceName in necessaryScripts) { var resourceAssemblyName = Assembly.GetExecutingAssembly().GetName().Name; var javaScriptName = $"{resourceAssemblyName}.{resourceName}"; var content = LoadResourceFromAssembly(Assembly.GetExecutingAssembly(), javaScriptName); var filename = javaScriptName.Substring(resourceAssemblyName.Length + 1); scripts.Append($" <script src=\"/{route}/{filename.Replace("Resources.OpenApi.", "")}\" > </script>{ Environment.NewLine}"); openApiFileReferences.Add(new OpenApiFileReference { Content = content, Filename = filename.Replace("Resources.OpenApi.", "OpenApi.") }); } scripts.Append(" </body>"); // Other necessary files var prefix = "FunctionMonkey.Compiler.Core.node_modules.swagger_ui_dist."; Assembly sourceAssembly = GetType().Assembly; var necessaryFiles = sourceAssembly .GetManifestResourceNames() .Where(x => x.StartsWith(prefix)).Select(name => (prefix, name)) .ToList(); prefix = "FunctionMonkey.Compiler.Core.Resources.OpenApi."; necessaryFiles.Add((prefix, "FunctionMonkey.Compiler.Core.Resources.OpenApi.swagger-logo.svg")); foreach (var necessaryFile in necessaryFiles) { var content = LoadResourceFromAssembly(sourceAssembly, necessaryFile.name); if (necessaryFile.name.EndsWith(".index.html")) { var documentInfo = configuration.OpenApiDocumentInfos .Where(x => x.Value.Selected) .Select(x => x.Value) .DefaultIfEmpty(configuration.OpenApiDocumentInfos.FirstOrDefault().Value) .First(); var contentString = Encoding.UTF8.GetString(content); contentString = contentString.Replace("http://petstore.swagger.io/v2/swagger.json", $"/{route}/{documentInfo.DocumentRoute}"); contentString = contentString.Replace("https://petstore.swagger.io/v2/swagger.json", $"/{route}/{documentInfo.DocumentRoute}"); contentString = contentString.Replace("=\"./swagger", $"=\"/{configuration.UserInterfaceRoute}/swagger"); contentString = contentString.Replace("href=\"./favicon-", "href=\"/openapi/favicon-"); contentString = contentString.Replace("</head>", links.ToString()); contentString = contentString.Replace("</body>", scripts.ToString()); content = Encoding.UTF8.GetBytes(contentString); } openApiFileReferences.Add(new OpenApiFileReference { Content = content, Filename = $"OpenApi.{necessaryFile.name.Substring(necessaryFile.prefix.Length)}" }); } }
public OpenApiBuilder(OpenApiConfiguration openApiConfiguration) { _openApiConfiguration = openApiConfiguration; }
/// <summary> /// Configure Open API hosting using an <see cref="IOpenApiHost"/>. /// </summary> /// <typeparam name="TRequest">The type of the request.</typeparam> /// <typeparam name="TResponse">The type of the response.</typeparam> /// <param name="services">The services collection to configure.</param> /// <param name="configureHost">A function used to configure the host.</param> /// <param name="configureEnvironment">A function used to optionally configure the hosting environment.</param> /// <returns>The configured <see cref="IServiceCollection"/>.</returns> /// <remarks> /// <para> /// See <see cref="IOpenApiService"/> for details on using the Open API hosting environment. /// </para> /// <para> /// To host in functions, you should provide a function entry point with a catch-all for your base URI, and any operation types you need to support (GET, POST etc.) /// </para> /// <para> /// <code> /// [FunctionName("openapihostroot")] /// public static Task<IActionResult> RunAsync([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "{*path}")]HttpRequest req, ExecutionContext context, ILogger log) /// { /// Initialize(context); /// /// var host = ServiceRoot.ServiceProvider.GetRequiredService<OpenApiHttpRequestHost>(); /// return host.HandleRequest(req); /// } /// </code> /// </para> /// <para> /// Initialization is handled using this method, during Functions container initialization. /// </para> /// <para> /// <code> /// private static void Initialize(ExecutionContext context) /// { /// Functions.InitializeContainer(context, services => /// { /// services.AddOpenApiHttpHosting(host => /// { /// using (var stream = File.OpenRead(".\\yaml\\petstore.yaml")) /// { /// var openApiDocument = new OpenApiStreamReader().Read(stream, out var diagnostics); /// host.AddDocument(openApiDocument); /// } /// }); /// /// // We can add all the services here /// services.AddSingleton<IOpenApiService, PetStoreService>(); /// }); /// } /// </code> /// </para> /// <para> /// You can add as many <see cref="IOpenApiService"/> instances to the container as you have, but the framework will /// <i>only</i> expose those that are bound to Open API documents that you have added to the host. While you typically /// add documents on startup, you can add more at runtime to light up services that are registered in the container, but not /// actually bound to Open API documents. /// </para> /// <para> /// See <see cref="IOpenApiService"/> for more details on configuring the host using this mechanism. /// </para> /// </remarks> public static IServiceCollection AddOpenApiHosting <TRequest, TResponse>( this IServiceCollection services, Action <OpenApiHostConfiguration>?configureHost, Action <IOpenApiConfiguration>?configureEnvironment = null) { if (services.Any(s => typeof(IOpenApiHost <TRequest, TResponse>).IsAssignableFrom(s.ServiceType))) { return(services); } services.AddJsonSerializerSettings(); services.AddInstrumentation(); services.AddOpenApiAuditing(); services.AddAuditLogSink <ConsoleAuditLogSink>(); services.AddSingleton <JsonConverter, OpenApiDocumentJsonConverter>(); services.AddSingleton <JsonConverter, HalDocumentJsonConverter>(); services.AddSingleton <IOpenApiDocumentProvider, OpenApiDocumentProvider>(); services.AddSingleton <IHalDocumentFactory, HalDocumentFactory>(); services.AddTransient <HalDocument>(); services.AddSingleton <IOpenApiServiceOperationLocator, DefaultOperationLocator>(); services.AddSingleton <IPathMatcher, PathMatcher>(); services.AddSingleton <IOpenApiService, SwaggerService>(); services.AddSingleton <IOpenApiLinkOperationMapper, OpenApiLinkOperationMapper>(); services.AddSingleton <IOpenApiAccessChecker, OpenApiAccessChecker>(); services.AddSingleton <IOpenApiExceptionMapper, OpenApiExceptionMapper>(); services.AddSingleton <IOpenApiWebLinkResolver, OpenApiWebLinkResolver>(); services.AddSingleton <IAuditContext, AuditContext>(); services.AddSingleton <IOpenApiOperationInvoker <TRequest, TResponse>, OpenApiOperationInvoker <TRequest, TResponse> >(); services.AddSingleton((Func <IServiceProvider, IOpenApiHost <TRequest, TResponse> >)(serviceProvider => { var result = new OpenApiHost <TRequest, TResponse>( serviceProvider.GetRequiredService <IPathMatcher>(), serviceProvider.GetRequiredService <IOpenApiContextBuilder <TRequest> >(), serviceProvider.GetRequiredService <IOpenApiOperationInvoker <TRequest, TResponse> >(), serviceProvider.GetRequiredService <IOpenApiResultBuilder <TResponse> >()); IOpenApiExceptionMapper exceptionMapper = serviceProvider.GetRequiredService <IOpenApiExceptionMapper>(); exceptionMapper.Map <OpenApiBadRequestException>(400); exceptionMapper.Map <OpenApiUnauthorizedException>(401); exceptionMapper.Map <OpenApiForbiddenException>(403); exceptionMapper.Map <OpenApiNotFoundException>(404); var hostConfiguration = new OpenApiHostConfiguration(serviceProvider.GetRequiredService <IOpenApiDocumentProvider>(), exceptionMapper, serviceProvider.GetRequiredService <IOpenApiLinkOperationMapper>()); serviceProvider.GetServices <IHalDocumentMapper>().ForEach(mapper => mapper.ConfigureLinkMap(hostConfiguration.Links)); configureHost?.Invoke(hostConfiguration); return(result); })); services.AddSingleton <IOpenApiConfiguration>(serviceProvider => { var config = new OpenApiConfiguration(serviceProvider); configureEnvironment?.Invoke(config); return(config); }); services.AddOpenApiJsonConverters(); services.AddOpenApiExceptionMappers(); return(services); }
public void Compile(IReadOnlyCollection <AbstractFunctionDefinition> functionDefinitions, OpenApiConfiguration openApiConfiguration, OpenApiOutputModel openApiOutputModel, string outputBinaryFolder) { HandlebarsHelperRegistration.RegisterHelpers(); HttpFunctionDefinition[] httpFunctionDefinitions = functionDefinitions .OfType <HttpFunctionDefinition>() .Where(x => !string.IsNullOrWhiteSpace(x.Route)) .ToArray(); if (!httpFunctionDefinitions.Any()) { return; } List <object> proxyDefinitions = new List <object>(httpFunctionDefinitions); if (openApiConfiguration.IsOpenApiOutputEnabled) { proxyDefinitions.Add(new { Name = "OpenApiYaml", Route = "/openapi.yaml", IsOpenApiYaml = true, }); Debug.Assert(openApiOutputModel != null); if (openApiOutputModel.IsConfiguredForUserInterface) { // The commented out code will do an explicit proxy per Swagger file // It goes wit the proxies.explicit.json.handlebars template /*StringBuilder proxyBuilder = new StringBuilder(); * int index = 0; * foreach (OpenApiFileReference reference in openApiOutputModel.SwaggerUserInterface) * { * proxyBuilder.AppendLine( * $",\"OpenAPIUI{index}\": {{\"matchCondition\":{{\"route\":\"/openapi/{reference.Filename}\",\"methods\":[\"GET\"]}},\"backendUri\":\"https://localhost/api/OpenApiProvider?name={reference.Filename}\"}}"); * * index++; * } * * proxyDefinitions.Add(new * { * IsOpenApiUi = true, * OpenApiUiProxies = proxyBuilder.ToString() * });*/ proxyDefinitions.Add(new { Name = "OpenApiProvider", Route = openApiConfiguration.UserInterfaceRoute + "/{name}", IsOpenApiUi = true }); } } string templateSource = _templateProvider.GetProxiesJsonTemplate(); Func <object, string> template = Handlebars.Compile(templateSource); string json = template(proxyDefinitions); DirectoryInfo folder = Directory.CreateDirectory(Path.Combine(outputBinaryFolder, "..")); string filename = Path.Combine(folder.FullName, "proxies.json"); using (Stream stream = new FileStream(filename, FileMode.Create)) using (StreamWriter writer = new StreamWriter(stream)) { writer.Write(json); } }
public OpenApiCompilerConfiguration(OpenApiConfiguration configuration) { foreach (var documentFilterFactory in configuration.DocumentFilterFactories) { DocumentFilters.Add(documentFilterFactory()); } foreach (var reDocDocumentFilterFactory in configuration.ReDocDocumentFilterFactories) { ReDocDocumentFilters.Add(reDocDocumentFilterFactory()); } foreach (var injectedExtensions in configuration.InjectedExtensions) { DocumentFilters.Add(new OpenApiExtensionInjectingDocumentFilter(injectedExtensions.resourceAssembly, injectedExtensions.resourceName, injectedExtensions.documentRoute)); } foreach (var reDocInjectedExtensions in configuration.ReDocInjectedExtensions) { ReDocDocumentFilters.Add(new OpenApiExtensionInjectingDocumentFilter(reDocInjectedExtensions.resourceAssembly, reDocInjectedExtensions.resourceName, reDocInjectedExtensions.documentRoute)); } foreach (var injectedTags in configuration.InjectedTags) { DocumentFilters.Add(new OpenApiTagInjectingDocumentFilter(injectedTags.resourceAssembly, injectedTags.resourceName, injectedTags.documentRoute)); } foreach (var reDocInjectedTags in configuration.ReDocInjectedTags) { ReDocDocumentFilters.Add(new OpenApiTagInjectingDocumentFilter(reDocInjectedTags.resourceAssembly, reDocInjectedTags.resourceName, reDocInjectedTags.documentRoute)); } foreach (var operationFilterFactory in configuration.OperationFilterFactories) { OperationFilters.Add(operationFilterFactory()); } foreach (var parameterFilterFactory in configuration.ParameterFilterFactories) { ParameterFilters.Add(parameterFilterFactory()); } foreach (var schemaFilterFactory in configuration.SchemaFilterFactories) { SchemaFilters.Add(schemaFilterFactory()); } foreach (var xmlDocFactory in configuration.XmlDocFactories) { SchemaFilters.Add(new OpenApiXmlCommentsSchemaFilter(xmlDocFactory())); } SchemaIdSelector = configuration.SchemaIdSelector; if (SchemaIdSelector == null) { SchemaIdSelector = type => { var typeName = type.GetAttributeValue((DataContractAttribute attribute) => attribute.Name) ?? type.FriendlyId(); return(typeName.SanitizeClassName()); }; } }