/// <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);
        }
Example #2
0
        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);
        }
Example #3
0
        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);
        }
Example #5
0
        /*** 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);
                            }
                        }
                    }
                }
            }
        }
Example #6
0
        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);
                            }
                        }
                    }
                }
            }
        }