示例#1
0
        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>()
                    }
                });
            }
        }
示例#2
0
        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());
                };
            }
        }
示例#4
0
        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);
        }
示例#5
0
        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)}"
                });
            }
        }
示例#6
0
        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);
        }
示例#7
0
        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)}"
                });
            }
        }
示例#8
0
 public OpenApiBuilder(OpenApiConfiguration openApiConfiguration)
 {
     _openApiConfiguration = openApiConfiguration;
 }
示例#9
0
        /// <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&lt;IActionResult&gt; RunAsync([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "{*path}")]HttpRequest req, ExecutionContext context, ILogger log)
        /// {
        ///     Initialize(context);
        ///
        ///     var host = ServiceRoot.ServiceProvider.GetRequiredService&lt;OpenApiHttpRequestHost&gt;();
        ///     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 =&gt;
        ///     {
        ///         services.AddOpenApiHttpHosting(host =&gt;
        ///         {
        ///             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&lt;IOpenApiService, PetStoreService&gt;();
        ///     });
        /// }
        /// </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);
                }
        }
示例#11
0
        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());
                };
            }
        }