public OpenApiDocument Build(string documentVersion) { OpenApiGeneratorConfig input = new OpenApiGeneratorConfig( annotationXmlDocuments: new List <XDocument>() { XDocument.Load(XDOCUMENT_PATH) }, assemblyPaths: new List <string>() { ASSEMBLY_PATH }, openApiDocumentVersion: documentVersion, filterSetVersion: FilterSetVersion.V1 ); GenerationDiagnostic result; OpenApiGenerator generator = new OpenApiGenerator(); IDictionary <DocumentVariantInfo, OpenApiDocument> documents = generator.GenerateDocuments(input, out result); foreach (OperationGenerationDiagnostic diagnostic in result.OperationGenerationDiagnostics) { foreach (GenerationError error in diagnostic.Errors) { Console.Write("OpenAPI Document Generation Error in " + diagnostic.OperationMethod + " " + diagnostic.Path); Console.Error.WriteLine(error.Message); } } return(documents[DocumentVariantInfo.Default]); }
public async Task <HttpResponseData> RunSwagger2([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequestData req, FunctionContext executionContext) { var input = new OpenApiGeneratorConfig( annotationXmlDocuments: new List <XDocument>() { XDocument.Load(@"AzureFunctionsOpenAPIDemo.xml"), }, assemblyPaths: new List <string>() { @"AzureFunctionsOpenAPIDemo.dll" }, openApiDocumentVersion: "V1", filterSetVersion: FilterSetVersion.V1 ); input.OpenApiInfoDescription = "This is a sample description..."; var generator = new OpenApiGenerator(); var openApiDocuments = generator.GenerateDocuments( openApiGeneratorConfig: input, generationDiagnostic: out GenerationDiagnostic result ); var response = req.CreateResponse(HttpStatusCode.OK); response.Headers.Add("Content", "Content-Type: application/json; charset=utf-8"); response.WriteString(openApiDocuments.First().Value.SerializeAsJson(OpenApiSpecVersion.OpenApi2_0)); return(response); }
public static async Task <HttpResponseMessage> RunSwagger([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log) { var input = new OpenApiGeneratorConfig( annotationXmlDocuments: new List <XDocument>() { XDocument.Load(@"AzureFunctionsOpenAPIDemo.xml"), }, assemblyPaths: new List <string>() { @"bin\AzureFunctionsOpenAPIDemo.dll" }, openApiDocumentVersion: "V1", filterSetVersion: FilterSetVersion.V1 ); input.OpenApiInfoDescription = "This is a sample description..."; var generator = new OpenApiGenerator(); var openApiDocuments = generator.GenerateDocuments( openApiGeneratorConfig: input, generationDiagnostic: out GenerationDiagnostic result ); return(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(openApiDocuments.First().Value.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0), Encoding.UTF8, "application/json") }); }
public void InvalidDocumentationShouldYieldFailure( string testCaseName, IList <string> inputXmlFiles, IList <string> inputBinaryFiles, int expectedOperationGenerationResultsCount, string expectedJsonFile, DocumentGenerationDiagnostic expectedDocumentGenerationResult, IList <OperationGenerationDiagnostic> expectedFailureOperationGenerationResults) { _output.WriteLine(testCaseName); var documents = new List <XDocument>(); documents.AddRange(inputXmlFiles.Select(XDocument.Load)); var input = new OpenApiGeneratorConfig(documents, inputBinaryFiles, "1.0.0", FilterSetVersion.V1); GenerationDiagnostic result; var generator = new OpenApiGenerator(); var openApiDocuments = generator.GenerateDocuments(input, out result); openApiDocuments.Should().NotBeNull(); result.DocumentGenerationDiagnostic.Should().BeEquivalentTo(expectedDocumentGenerationResult); result.OperationGenerationDiagnostics.Count.Should().Be(expectedOperationGenerationResultsCount); openApiDocuments[DocumentVariantInfo.Default].Should().NotBeNull(); var failurePaths = result.OperationGenerationDiagnostics.Where( p => p.Errors.Count > 0) .ToList(); var actualDocument = openApiDocuments[DocumentVariantInfo.Default] .SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); var expectedDocument = File.ReadAllText(expectedJsonFile); _output.WriteLine(actualDocument); failurePaths.Should().BeEquivalentTo(expectedFailureOperationGenerationResults); // We are doing serialization and deserialization to force the resulting actual document // to have the exact fields we will see in the resulting document based on the contract resolver. // Without serialization and deserialization, the actual document may have fields that should // not be present, such as empty list fields. var openApiStringReader = new OpenApiStringReader(); var actualDeserializedDocument = openApiStringReader.Read( actualDocument, out OpenApiDiagnostic diagnostic); diagnostic.Errors.Count.Should().Be(0); actualDeserializedDocument .Should() .BeEquivalentTo(openApiStringReader.Read(expectedDocument, out var _)); }
public void GenerateDocumentWithOperationConfigShouldSucceed( string testCaseName, IList <string> inputXmlFiles, IList <string> inputBinaryFiles, string configXmlFile, int expectedOperationGenerationResultsCount, string expectedJsonFile) { _output.WriteLine(testCaseName); var documents = new List <XDocument>(); documents.AddRange(inputXmlFiles.Select(XDocument.Load)); var configDocument = XDocument.Load(configXmlFile); var generator = new OpenApiGenerator(); var input = new OpenApiGeneratorConfig(documents, inputBinaryFiles, "1.0.0", FilterSetVersion.V1) { AdvancedConfigurationXmlDocument = configDocument }; GenerationDiagnostic result; var openApiDocuments = generator.GenerateDocuments( input, out result); result.Should().NotBeNull(); result.DocumentGenerationDiagnostic.Errors.Count.Should().Be(0); openApiDocuments[DocumentVariantInfo.Default].Should().NotBeNull(); result.OperationGenerationDiagnostics.Count.Should().Be(expectedOperationGenerationResultsCount); var actualDocument = openApiDocuments[DocumentVariantInfo.Default] .SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); var expectedDocument = File.ReadAllText(expectedJsonFile); _output.WriteLine(actualDocument); var openApiStringReader = new OpenApiStringReader(); var actualDeserializedDocument = openApiStringReader.Read( actualDocument, out OpenApiDiagnostic diagnostic); diagnostic.Errors.Count.Should().Be(0); actualDeserializedDocument .Should() .BeEquivalentTo( openApiStringReader.Read(expectedDocument, out var _), o => o.WithStrictOrdering()); }
public void ValidDocumentationShouldReturnCorrectDocument( string testCaseName, IList <string> inputXmlFiles, IList <string> inputBinaryFiles, string openApiDocumentVersion, int expectedOperationGenerationResultsCount, string expectedJsonFile) { _output.WriteLine(testCaseName); var documents = new List <XDocument>(); documents.AddRange(inputXmlFiles.Select(XDocument.Load)); var input = new OpenApiGeneratorConfig( documents, inputBinaryFiles, openApiDocumentVersion, FilterSetVersion.V1); GenerationDiagnostic result; var generator = new OpenApiGenerator(); var openApiDocuments = generator.GenerateDocuments(input, out result); result.Should().NotBeNull(); result.DocumentGenerationDiagnostic.Errors.Count.Should().Be(0); openApiDocuments[DocumentVariantInfo.Default].Should().NotBeNull(); result.OperationGenerationDiagnostics.Count(p => p.Errors.Count > 0).Should().Be(0); result.OperationGenerationDiagnostics.Count.Should().Be(expectedOperationGenerationResultsCount); var actualDocument = openApiDocuments[DocumentVariantInfo.Default] .SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); var expectedDocument = File.ReadAllText(expectedJsonFile); _output.WriteLine(actualDocument); var openApiStringReader = new OpenApiStringReader(); var actualDeserializedDocument = openApiStringReader.Read( actualDocument, out OpenApiDiagnostic diagnostic); diagnostic.Errors.Count.Should().Be(0); actualDeserializedDocument .Should() .BeEquivalentTo(openApiStringReader.Read(expectedDocument, out var _)); }
public async Task <JObject> Get() { var reference = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); var g = new OpenApiGenerator <BaseController, OrderCloudIntegrationsAuthAttribute>() .CollectMetaData(Path.Combine(reference, "reference.md"), ErrorCodes.All) .DefineSpec(new SwaggerConfig() { Name = "Headstart", ContactEmail = "*****@*****.**", Description = "Headstart API", Host = _settings.EnvironmentSettings.MiddlewareBaseUrl, Title = "Headstart API", Url = "https://ordercloud.io", Version = "1.0" }); return(await Task.FromResult(g.Specification())); }
private static OpenApiOperation?GetOperationForEndpoint(RouteEndpointBuilder routeEndpointBuilder) { var pattern = routeEndpointBuilder.RoutePattern; var metadata = new EndpointMetadataCollection(routeEndpointBuilder.Metadata); var methodInfo = metadata.OfType <MethodInfo>().SingleOrDefault(); var serviceProvider = routeEndpointBuilder.ServiceProvider; if (methodInfo == null || serviceProvider == null) { return(null); } var hostEnvironment = serviceProvider.GetService <IHostEnvironment>(); var serviceProviderIsService = serviceProvider.GetService <IServiceProviderIsService>(); var generator = new OpenApiGenerator(hostEnvironment, serviceProviderIsService); return(generator.GetOpenApiOperation(methodInfo, metadata, pattern)); }
public void NoOperationsToParseShouldReturnEmptyDocument(string openApiDocumentVersion) { var path = Path.Combine(InputDirectory, "AnnotationNoOperationsToParse.xml"); var document = XDocument.Load(path); var input = new OpenApiGeneratorConfig( new List <XDocument>() { document }, new List <string>(), openApiDocumentVersion, FilterSetVersion.V1); GenerationDiagnostic result; var generator = new OpenApiGenerator(); var openApiDocument = generator.GenerateDocument(input, out result); result.Should().NotBeNull(); openApiDocument.Should().BeNull(); result.DocumentGenerationDiagnostic.Should() .BeEquivalentTo( new DocumentGenerationDiagnostic { Errors = { new GenerationError { Message = SpecificationGenerationMessages.NoOperationElementFoundToParse, } } } ); }
private static void AddAndConfigureOperationForEndpoint(EndpointBuilder endpointBuilder, Func<OpenApiOperation, OpenApiOperation>? configure = null) { foreach (var item in endpointBuilder.Metadata) { if (item is OpenApiOperation existingOperation) { if (configure is not null) { var configuredOperation = configure(existingOperation); if (!ReferenceEquals(configuredOperation, existingOperation)) { endpointBuilder.Metadata.Remove(existingOperation); // The only way configureOperation could be null here is if configureOperation violated it's signature and returned null. // We could throw or something, removing the previous metadata seems fine. if (configuredOperation is not null) { endpointBuilder.Metadata.Add(configuredOperation); } } } return; } } // We cannot generate an OpenApiOperation without routeEndpointBuilder.RoutePattern. if (endpointBuilder is not RouteEndpointBuilder routeEndpointBuilder) { return; } var pattern = routeEndpointBuilder.RoutePattern; var metadata = new EndpointMetadataCollection(routeEndpointBuilder.Metadata); var methodInfo = metadata.OfType<MethodInfo>().SingleOrDefault(); if (methodInfo is null) { return; } var applicationServices = routeEndpointBuilder.ApplicationServices; var hostEnvironment = applicationServices.GetService<IHostEnvironment>(); var serviceProviderIsService = applicationServices.GetService<IServiceProviderIsService>(); var generator = new OpenApiGenerator(hostEnvironment, serviceProviderIsService); var newOperation = generator.GetOpenApiOperation(methodInfo, metadata, pattern); if (newOperation is not null) { if (configure is not null) { newOperation = configure(newOperation); } if (newOperation is not null) { routeEndpointBuilder.Metadata.Add(newOperation); } } }
public void GenerateDocumentMultipleVariantsShouldSucceed( string testCaseName, IList <string> inputXmlFiles, IList <string> inputBinaryFiles, string configXmlFile, int expectedOperationGenerationResultsCount, IDictionary <DocumentVariantInfo, string> documentVariantInfoToExpectedJsonFileMap) { _output.WriteLine(testCaseName); // Arrange var documents = new List <XDocument>(); documents.AddRange(inputXmlFiles.Select(XDocument.Load)); var configPath = configXmlFile; var configDocument = XDocument.Load(configPath); var generator = new OpenApiGenerator(); var input = new OpenApiGeneratorConfig(documents, inputBinaryFiles, "1.0.0", FilterSetVersion.V1) { AdvancedConfigurationXmlDocument = configDocument }; GenerationDiagnostic result; // Act var openApiDocuments = generator.GenerateDocuments(input, out result); result.Should().NotBeNull(); result.DocumentGenerationDiagnostic.Errors.Count.Should().Be(0); result.OperationGenerationDiagnostics.Count(r => r.Errors.Count == 0) .Should() .Be(expectedOperationGenerationResultsCount); openApiDocuments.Keys.Should() .BeEquivalentTo(documentVariantInfoToExpectedJsonFileMap.Keys); var actualDocuments = new List <OpenApiDocument>(); var expectedDocuments = new List <OpenApiDocument>(); foreach (var documentVariantInfoToExpectedJsonFile in documentVariantInfoToExpectedJsonFileMap) { // Verify each document variant against a json file content. var documentVariantInfo = documentVariantInfoToExpectedJsonFile.Key; var expectedJsonFile = documentVariantInfoToExpectedJsonFile.Value; openApiDocuments.TryGetValue(documentVariantInfo, out var specificationDocument); var actualDocumentAsString = specificationDocument.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); _output.WriteLine(actualDocumentAsString); var openApiStringReader = new OpenApiStringReader(); var actualDeserializedDocument = openApiStringReader.Read( actualDocumentAsString, out OpenApiDiagnostic diagnostic); diagnostic.Errors.Count.Should().Be(0); actualDeserializedDocument .Should() .BeEquivalentTo(openApiStringReader.Read(File.ReadAllText(expectedJsonFile), out var _)); // Bug in fluent assertion method. Comparing the array of documents yields incorrect result. // Root cause unknown. This should be enabled once that bug is resolved. //actualDocuments.Add(actualDocument); //expectedDocuments.Add(expectedDocument); } //actualDocuments.Should().BeEquivalentTo(expectedDocuments); }
public static IActionResult Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "openapi")] HttpRequestMessage req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); var httpClient = new HttpClient() { BaseAddress = new Uri("https://raw.githubusercontent.com/OAI/OpenAPI-Specification/") }; //var openApiDocument = GenerateOpenApiDocument(); var openApiInfo = new OpenApiInfo() { Title = "ComplexOpenApiExample", Description = "A complex open api example", Version = "1.0.0", }; var restEndpoints = new List <RestEndpoint>() { new RestEndpoint() { Path = "/FetchOrders", InputOperations = new List <InputOperation>() { new InputOperation() { OperationType = OperationType.Get, Description = "Get an order", ResponseValues = new List <ResponseValue>() { new ResponseValue() { Name = "200", Description = "A good response", MediaType = "application/json", ResponseModelType = typeof(Order), StatusCode = HttpStatusCode.OK, } } } }, InputParameters = new List <InputParameter>() { new InputParameter() { Name = "QueryString", Description = "A querystring", ParameterLocation = ParameterLocation.Query, } }, }, }; var responseValues = restEndpoints.SelectMany(re => re.InputOperations) .SelectMany(io => io.ResponseValues); var types = responseValues .Select(rv => rv.ResponseModelType); var openApiGenerator = new OpenApiGenerator(); var openApiDocument = openApiGenerator.GenerateDocument(openApiInfo, restEndpoints, responseValues, types); var openApiString = openApiDocument.Serialize(OpenApiSpecVersion.OpenApi3_0, OpenApiFormat.Json); return(new OkObjectResult(openApiString)); }
public HttpResponseMessage GenerateSwagger([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log, ExecutionContext ctx) { try { log.LogInformation("Starting Swagger Retrieval"); var documentPath = Path.GetFullPath(Path.Combine(ctx.FunctionAppDirectory, $"{FunctionConstants.FunctionName}.xml")); var binaryPath = Path.GetFullPath(Path.Combine(ctx.FunctionAppDirectory, $"bin\\{FunctionConstants.FunctionName}.dll")); log.LogDebug($"Looking for Documentation : {documentPath}"); log.LogDebug($"Looking for Binary : {binaryPath}"); var input = new OpenApiGeneratorConfig( annotationXmlDocuments: new List <XDocument>() { XDocument.Load(documentPath), }, assemblyPaths: new List <string>() { binaryPath }, openApiDocumentVersion: "V1", filterSetVersion: FilterSetVersion.V1 ); input.OpenApiInfoDescription = _options.ServiceDescription ?? FunctionConstants.FunctionName; var generator = new OpenApiGenerator(); var openApiDocuments = generator.GenerateDocuments( openApiGeneratorConfig: input, generationDiagnostic: out GenerationDiagnostic result ); OpenApiSpecVersion openApiVersion; switch (_options.OpenApiVersion) { default: openApiVersion = OpenApiSpecVersion.OpenApi2_0; break; case "V3": openApiVersion = OpenApiSpecVersion.OpenApi3_0; break; } //switch the hostname for current known var definition = openApiDocuments.First().Value; definition.Info.Title = _options.ServiceTitle ?? FunctionConstants.FunctionName; if (definition.Servers.Any()) { var hostname = $"https://{Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME")}"; //string hostname = ""; //bool.TryParse(Environment.GetEnvironmentVariable("HTTPS"), out bool sslOn); //if (sslOn) //{ // hostname = $"https://{Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME")}"; //} //else // hostname = $"http://{Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME")}"; log.LogInformation($"Server Name Switch : Swapping [{definition.Servers.First().Url}] for [{hostname}]"); definition.Servers.First().Url = hostname; } return(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(definition.SerializeAsJson(openApiVersion), Encoding.UTF8, "application/json") }); } catch (Exception ex) { log.LogCritical("Exception Encountered", ex); throw; } }