/// <summary> /// Fetches the URL value and creates multiple operations based on optional parameters. /// </summary> /// <param name="paths">The paths to be updated.</param> /// <param name="element">The xml element representing an operation in the annotation xml.</param> /// <param name="settings">The operation filter settings.</param> /// <returns>The list of generation errors, if any produced when processing the filter.</returns> public IList <GenerationError> Apply( OpenApiPaths paths, XElement element, PreProcessingOperationFilterSettings settings) { var generationErrors = new List <GenerationError>(); try { var paramElements = element.Elements() .Where( p => p.Name == KnownXmlStrings.Param) .ToList(); // We need both the full URL and the absolute paths for processing. // Full URL contains all path and query parameters. // Absolute path is needed to get OperationId parsed out correctly. var fullUrl = element.Elements() .FirstOrDefault(p => p.Name == KnownXmlStrings.Url) ?.Value; var absolutePath = fullUrl.UrlStringToAbsolutePath(); var operationMethod = (OperationType)Enum.Parse( typeof(OperationType), element.Elements().FirstOrDefault(p => p.Name == KnownXmlStrings.Verb)?.Value, ignoreCase: true); var allGeneratedPathStrings = GeneratePossiblePaths( absolutePath, paramElements.Where( p => p.Attribute(KnownXmlStrings.In)?.Value == KnownXmlStrings.Path) .ToList()); foreach (var pathString in allGeneratedPathStrings) { if (!paths.ContainsKey(pathString)) { paths[pathString] = new OpenApiPathItem(); } paths[pathString].Operations[operationMethod] = new OpenApiOperation { OperationId = OperationHandler.GetOperationId(pathString, operationMethod) }; } } catch (Exception ex) { generationErrors.Add( new GenerationError { Message = ex.Message, ExceptionType = ex.GetType().Name }); } return(generationErrors); }
private OpenApiPaths GeneratePaths(IEnumerable <ServiceEntry> apiDescriptions, SchemaRepository schemaRepository) { var apiDescriptionsByPath = apiDescriptions.OrderBy(p => p.RoutePath) .GroupBy(apiDesc => apiDesc.Descriptor.Id); var paths = new OpenApiPaths(); foreach (var group in apiDescriptionsByPath) { var key = $"/{group.Min(p => p.RoutePath).TrimStart('/')}".Trim(); if (!paths.ContainsKey(key)) { paths.Add(key, new OpenApiPathItem { Operations = GenerateOperations(group, schemaRepository) }); } else { paths.Add($"/{group.Min(p => $" {p.RoutePath}( {string.Join("_", p.Parameters.Select(m => m.ParameterType.Name))})")}", new OpenApiPathItem { Operations = GenerateOperations(group, schemaRepository) }); } } ; return(paths); }
public static OpenApiPaths Paths(params KeyValuePair <string, OpenApiPathItem>[] pathItems) { var paths = new OpenApiPaths(); foreach (var pathItem in pathItems) { if (!paths.ContainsKey(pathItem.Key)) { paths.Add(pathItem.Key, pathItem.Value); } } return(paths); }
/// <inheritdoc /> public OpenApiPathItem GetOpenApiPath(string path, OpenApiPaths paths) { var item = paths.ContainsKey(path) ? paths[path] : new OpenApiPathItem(); return(item); }
/*** API document comparison checks ***/ private void CheckForApiRouteAndHttpMethodAdditions(OpenApiDocument previousApiDocument, OpenApiDocument freshApiDocument, DiffReport diffReport) { // Get information for all routes in previous API documentation OpenApiPaths previousApiDocumentRoutes = previousApiDocument.Paths; // Get information for all routes in fresh API documentation OpenApiPaths freshApiDocumentRoutes = freshApiDocument.Paths; // Iterate over all routes in freshly downloaded API documentation foreach (KeyValuePair <string, OpenApiPathItem> route in freshApiDocumentRoutes) { // Find current API route as string string currentApiRoute = route.Key; // Check if this route in the fresh API documentation in a new addition if (!previousApiDocumentRoutes.ContainsKey(currentApiRoute)) { // NOTE: New route detected, therefore all HTTP methods associated with this route are new // Find all HTTP methods associated with this route (HTTP methods represented as enum type OpenApi.Models.OperationType) OpenApiPathItem newApiRouteValue = route.Value; IDictionary <OperationType, OpenApiOperation> newApiRouteHttpMethodsDict = newApiRouteValue.Operations; // Verify route has associated HTTP methods if (newApiRouteHttpMethodsDict.Count > 0) { // Get list of all HTTP methods associated with this new route IList <OperationType> newApiRouteHttpMethodTypes = new List <OperationType>(newApiRouteHttpMethodsDict.Keys); // Iterate through the new route's HTTP methods foreach (OperationType newApiRouteHttpMethod in newApiRouteHttpMethodTypes) { // Save added route/HTTP method information for API diff report diffReport.RecordAddedRouteInformation(currentApiRoute, newApiRouteHttpMethod); } } } else { // Previous API documentation already has this API route, check if there are any new HTTP methods for the existing route // Get dictionary of HTTP methods for current route from fresh API documentation OpenApiPathItem freshApiDocumentRouteValue = route.Value; IDictionary <OperationType, OpenApiOperation> freshApiDocumentRouteInfo = freshApiDocumentRouteValue.Operations; // Get dictionary of HTTP methods for current route from previous API documentation OpenApiPathItem previousApiDocumentRouteValue = previousApiDocumentRoutes[currentApiRoute]; IDictionary <OperationType, OpenApiOperation> previousApiDocumentRouteInfo = previousApiDocumentRouteValue.Operations; // Verify that fresh API documentation for this route contains HTTP methods if (freshApiDocumentRouteInfo.Count > 0) { // For this route, get list of HTTP methods in fresh API documentation IList <OperationType> freshApiRouteHttpMethods = new List <OperationType>(freshApiDocumentRouteInfo.Keys); // For this route, get list of HTTP methods in previous API documentation IList <OperationType> previousApiRouteHttpMethods = new List <OperationType>(previousApiDocumentRouteInfo.Keys); // Iterate over all HTTP methods listed in fresh API documentation for this route foreach (OperationType freshHttpMethod in freshApiRouteHttpMethods) { // For this route, if an HTTP method exists in fresh API documentation but not previous API documentation, // We have found a new API endpoint if (!previousApiRouteHttpMethods.Contains(freshHttpMethod)) { // Record newly detected API endpoint in diff report object diffReport.RecordAddedRouteInformation(currentApiRoute, freshHttpMethod); } } } } } }
private void CheckForApiRouteAndHttpMethodRemovals(OpenApiDocument previousApiDocument, OpenApiDocument freshApiDocument, DiffReport diffReport) { // Get information for all routes in previous API documentation OpenApiPaths previousApiDocumentRoutes = previousApiDocument.Paths; // Get information for all routes in fresh API documentation OpenApiPaths freshApiDocumentRoutes = freshApiDocument.Paths; // Iterate over all routes in previously stored API documentation foreach (KeyValuePair <string, OpenApiPathItem> route in previousApiDocumentRoutes) { // Find current API route as string string currentApiRoute = route.Key; // Check if this route in the previously downloaded API documentation has been removed if (!freshApiDocumentRoutes.ContainsKey(currentApiRoute)) { // NOTE: This route has been removed, therefore all HTTP methods associated with this route have been removed // Find all HTTP methods associated with this route (HTTP methods represented as enum type OpenApi.Models.OperationType) OpenApiPathItem removedApiRouteValue = route.Value; IDictionary <OperationType, OpenApiOperation> removedApiRouteHttpMethodsDict = removedApiRouteValue.Operations; // Verify route has associated HTTP methods if (removedApiRouteHttpMethodsDict.Count > 0) { // Get list of all HTTP methods associated with this removed route IList <OperationType> removedApiRouteHttpMethodTypes = new List <OperationType>(removedApiRouteHttpMethodsDict.Keys); // Iterate through the removed route's HTTP methods foreach (OperationType removedApiRouteHttpMethod in removedApiRouteHttpMethodTypes) { // Save removed route/HTTP method information for API diff report diffReport.RecordRemovedRouteInformation(currentApiRoute, removedApiRouteHttpMethod); } } } else { // New API documentation has this route, check if any HTTP methods have been removed // Get dictionary of HTTP methods for current route from previous API documentation OpenApiPathItem previousApiDocumentRouteValue = route.Value; IDictionary <OperationType, OpenApiOperation> previousApiDocumentRouteInfo = previousApiDocumentRouteValue.Operations; // Get dictionary of HTTP methods for current API route from fresh API documentation OpenApiPathItem freshApiRouteValue = freshApiDocumentRoutes[currentApiRoute]; IDictionary <OperationType, OpenApiOperation> freshApiDocumentRouteInfo = freshApiRouteValue.Operations; // Verify that previous API documentation for this route contains HTTP methods if (previousApiDocumentRouteInfo.Count > 0) { // For this route, get list of HTTP methods in previous API documentation IList <OperationType> previousApiRouteHttpMethods = new List <OperationType>(previousApiDocumentRouteInfo.Keys); // For this route, get list of HTTP methods in fresh API documentation IList <OperationType> freshApiRouteHttpMethods = new List <OperationType>(freshApiDocumentRouteInfo.Keys); // Iterate over all HTTP methods listted in previous API documentation for this route foreach (OperationType previousHttpMethod in previousApiRouteHttpMethods) { // For this route, if an HTTP method exists in previous API documentation but not fresh API documentation, // We have detected the removal of an API endpoint if (!freshApiRouteHttpMethods.Contains(previousHttpMethod)) { // Record removal of API endpoint in diff report object diffReport.RecordRemovedRouteInformation(currentApiRoute, previousHttpMethod); } } } } } }