Ejemplo n.º 1
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);
        }
Ejemplo n.º 2
0
        private void CreateSchemas(HttpFunctionDefinition[] functionDefinitions, OpenApiDocument openApiDocument, SchemaReferenceRegistry registry)
        {
            foreach (HttpFunctionDefinition functionDefinition in functionDefinitions)
            {
                if (functionDefinition.Verbs.Contains(HttpMethod.Post) ||
                    functionDefinition.Verbs.Contains(HttpMethod.Put))
                {
                    registry.FindOrAddReference(functionDefinition.CommandType);
                }
                if (functionDefinition.CommandResultType != null)
                {
                    registry.FindOrAddReference(functionDefinition.CommandResultType);
                }
            }

            if (registry.References.Any())
            {
                openApiDocument.Components.Schemas = registry.References;
            }
        }
Ejemplo n.º 3
0
        private static void CreateOperationsFromRoutes(HttpFunctionDefinition[] functionDefinitions,
                                                       OpenApiDocument openApiDocument, SchemaReferenceRegistry registry, string apiPrefix)
        {
            string prependedApiPrefix = string.IsNullOrEmpty(apiPrefix) ? $"" : $"/{apiPrefix}";
            var    operationsByRoute  = functionDefinitions.Where(x => x.Route != null).GroupBy(x => $"{prependedApiPrefix}/{x.Route}");

            foreach (IGrouping <string, HttpFunctionDefinition> route in operationsByRoute)
            {
                OpenApiPathItem pathItem = new OpenApiPathItem()
                {
                    Operations = new Dictionary <OperationType, OpenApiOperation>()
                };

                foreach (HttpFunctionDefinition functionByRoute in route)
                {
                    Type commandType = functionByRoute.CommandType;
                    foreach (HttpMethod method in functionByRoute.Verbs)
                    {
                        OpenApiOperation operation = new OpenApiOperation
                        {
                            Description = functionByRoute.OpenApiDescription,
                            Responses   = new OpenApiResponses(),
                            Tags        = string.IsNullOrWhiteSpace(functionByRoute.RouteConfiguration.OpenApiName) ? null : new List <OpenApiTag>()
                            {
                                new OpenApiTag {
                                    Name = functionByRoute.RouteConfiguration.OpenApiName
                                }
                            }
                        };
                        foreach (KeyValuePair <int, string> kvp in functionByRoute.OpenApiResponseDescriptions)
                        {
                            operation.Responses.Add(kvp.Key.ToString(), new OpenApiResponse
                            {
                                Description = kvp.Value
                            });
                        }

                        if (!operation.Responses.ContainsKey("200"))
                        {
                            OpenApiResponse response = new OpenApiResponse
                            {
                                Description = "Successful API operation"
                            };
                            if (functionByRoute.CommandResultType != null)
                            {
                                OpenApiSchema schema = registry.FindOrAddReference(functionByRoute.CommandResultType);
                                response.Content = new Dictionary <string, OpenApiMediaType>
                                {
                                    { "application/json", new OpenApiMediaType {
                                          Schema = schema
                                      } }
                                };
                            }
                            operation.Responses.Add("200", response);
                        }

                        string lowerCaseRoute = functionByRoute.Route;
                        foreach (HttpParameter property in functionByRoute.PossibleBindingProperties)
                        {
                            if (method == HttpMethod.Get || method == HttpMethod.Delete)
                            {
                                operation.Parameters.Add(new OpenApiParameter
                                {
                                    Name        = property.Name.ToCamelCase(),
                                    In          = ParameterLocation.Query,
                                    Required    = !property.IsOptional,
                                    Schema      = property.Type.MapToOpenApiSchema(),
                                    Description = ""
                                });
                            }
                        }

                        if (functionByRoute.Authorization == AuthorizationTypeEnum.Function && method == HttpMethod.Get || method == HttpMethod.Delete)
                        {
                            operation.Parameters.Add(new OpenApiParameter
                            {
                                Name        = "code",
                                In          = ParameterLocation.Query,
                                Required    = true,
                                Schema      = typeof(string).MapToOpenApiSchema(),
                                Description = ""
                            });
                        }

                        foreach (HttpParameter property in functionByRoute.RouteParameters)
                        {
                            operation.Parameters.Add(new OpenApiParameter
                            {
                                Name        = property.RouteName.ToCamelCase(),
                                In          = ParameterLocation.Path,
                                Required    = !property.IsOptional,
                                Schema      = property.Type.MapToOpenApiSchema(),
                                Description = ""
                            });
                            // TODO: We need to consider what to do with the payload model here - if its a route parameter
                            // we need to ignore it in the payload model
                        }

                        if (method == HttpMethod.Post || method == HttpMethod.Put || method == HttpMethod.Patch)
                        {
                            OpenApiRequestBody requestBody = new OpenApiRequestBody();
                            OpenApiSchema      schema      = registry.FindReference(commandType);
                            requestBody.Content = new Dictionary <string, OpenApiMediaType>
                            {
                                { "application/json", new OpenApiMediaType {
                                      Schema = schema
                                  } }
                            };
                            operation.RequestBody = requestBody;
                        }


                        pathItem.Operations.Add(MethodToOperationMap[method], operation);
                    }
                }

                openApiDocument.Paths.Add(route.Key, pathItem);
            }
        }
Ejemplo n.º 4
0
        private static void CreateOperationsFromRoutes(HttpFunctionDefinition[] functionDefinitions,
                                                       OpenApiDocument openApiDocument, SchemaReferenceRegistry registry, string apiPrefix, OpenApiCompilerConfiguration compilerConfiguration)
        {
            string prependedApiPrefix = string.IsNullOrEmpty(apiPrefix) ? $"" : $"/{apiPrefix}";
            var    operationsByRoute  = functionDefinitions.Where(x => x.Route != null).GroupBy(x => $"{prependedApiPrefix}/{x.Route}");

            foreach (IGrouping <string, HttpFunctionDefinition> route in operationsByRoute)
            {
                OpenApiPathItem pathItem = new OpenApiPathItem()
                {
                    Operations = new Dictionary <OperationType, OpenApiOperation>()
                };

                foreach (HttpFunctionDefinition functionByRoute in route)
                {
                    Type commandType = functionByRoute.CommandType;
                    foreach (HttpMethod method in functionByRoute.Verbs)
                    {
                        OpenApiOperation operation = new OpenApiOperation
                        {
                            Description = functionByRoute.OpenApiDescription,
                            Summary     = functionByRoute.OpenApiSummary,
                            Responses   = new OpenApiResponses(),
                            Tags        = string.IsNullOrWhiteSpace(functionByRoute.RouteConfiguration.OpenApiName) ? null : new List <OpenApiTag>()
                            {
                                new OpenApiTag {
                                    Name = functionByRoute.RouteConfiguration.OpenApiName
                                }
                            }
                        };

                        var operationFilterContext = new OpenApiOperationFilterContext
                        {
                            CommandType   = commandType,
                            PropertyNames = new Dictionary <string, string>()
                        };

                        foreach (KeyValuePair <int, OpenApiResponseConfiguration> kvp in functionByRoute.OpenApiResponseConfigurations)
                        {
                            operation.Responses.Add(kvp.Key.ToString(), new OpenApiResponse
                            {
                                Description = kvp.Value.Description,
                                Content     =
                                {
                                    ["application/json"] = new OpenApiMediaType()
                                    {
                                    Schema = kvp.Value.ResponseType == null ? null : registry.FindOrAddReference(kvp.Value.ResponseType)
                                    }
                                }
                            });
                        }

                        // Does any HTTP success response (2xx) exist
                        if (operation.Responses.Keys.FirstOrDefault(x => x.StartsWith("2")) == null)
                        {
                            OpenApiResponse response = new OpenApiResponse
                            {
                                Description = "Successful API operation"
                            };
                            if (functionByRoute.CommandResultType != null)
                            {
                                OpenApiSchema schema = registry.FindOrAddReference(functionByRoute.CommandResultType);
                                response.Content = new Dictionary <string, OpenApiMediaType>
                                {
                                    { "application/json", new OpenApiMediaType {
                                          Schema = schema
                                      } }
                                };
                            }
                            operation.Responses.Add("200", response);
                        }

                        if (method == HttpMethod.Get || method == HttpMethod.Delete)
                        {
                            var schema = registry.GetOrCreateSchema(commandType);
                            foreach (HttpParameter property in functionByRoute.PossibleBindingProperties)
                            {
                                var propertyInfo = commandType.GetProperty(property.Name);

                                // Property Name
                                var propertyName = propertyInfo.GetAttributeValue((JsonPropertyAttribute attribute) => attribute.PropertyName);
                                if (string.IsNullOrWhiteSpace(propertyName))
                                {
                                    propertyName = propertyInfo.GetAttributeValue((DataMemberAttribute attribute) => attribute.Name);
                                }
                                if (string.IsNullOrWhiteSpace(propertyName))
                                {
                                    propertyName = propertyInfo.Name.ToCamelCase();
                                }

                                // Property Required
                                var propertyRequired = !property.IsOptional;
                                if (!propertyRequired)
                                {
                                    propertyRequired = propertyInfo.GetAttributeValue((JsonPropertyAttribute attribute) => attribute.Required) == Required.Always;
                                }
                                if (!propertyRequired)
                                {
                                    propertyRequired = propertyInfo.GetAttributeValue((RequiredAttribute attribute) => attribute) != null;
                                }

                                var propertySchema = schema.Properties[propertyName];

                                var parameter = new OpenApiParameter
                                {
                                    Name        = propertyName,
                                    In          = ParameterLocation.Query,
                                    Required    = propertyRequired,
                                    Schema      = propertySchema, // property.Type.MapToOpenApiSchema(),
                                    Description = propertySchema.Description
                                };

                                FilterParameter(compilerConfiguration.ParameterFilters, parameter);

                                operation.Parameters.Add(parameter);
                                operationFilterContext.PropertyNames[parameter.Name] = propertyInfo.Name;
                            }
                        }

                        if (functionByRoute.Authorization == AuthorizationTypeEnum.Function && (method == HttpMethod.Get || method == HttpMethod.Delete))
                        {
                            operation.Parameters.Add(new OpenApiParameter
                            {
                                Name        = "code",
                                In          = ParameterLocation.Query,
                                Required    = true,
                                Schema      = typeof(string).MapToOpenApiSchema(),
                                Description = ""
                            });
                        }

                        foreach (HttpParameter property in functionByRoute.RouteParameters)
                        {
                            var parameter = new OpenApiParameter
                            {
                                Name        = property.RouteName.ToCamelCase(),
                                In          = ParameterLocation.Path,
                                Required    = !property.IsOptional,
                                Schema      = property.Type.MapToOpenApiSchema(),
                                Description = ""
                            };

                            FilterParameter(compilerConfiguration.ParameterFilters, parameter);

                            operation.Parameters.Add(parameter);
                            // TODO: We need to consider what to do with the payload model here - if its a route parameter
                            // we need to ignore it in the payload model
                        }

                        if (method == HttpMethod.Post || method == HttpMethod.Put || method == HttpMethod.Patch)
                        {
                            OpenApiRequestBody requestBody = new OpenApiRequestBody();
                            OpenApiSchema      schema      = registry.FindReference(commandType);
                            requestBody.Content = new Dictionary <string, OpenApiMediaType>
                            {
                                { "application/json", new OpenApiMediaType {
                                      Schema = schema
                                  } }
                            };
                            operation.RequestBody = requestBody;
                        }

                        FilterOperation(compilerConfiguration.OperationFilters, operation, operationFilterContext);

                        pathItem.Operations.Add(MethodToOperationMap[method], operation);
                    }
                }

                openApiDocument.Paths.Add(route.Key, pathItem);
            }
        }