public void GetOpenApiSchemas_Result_Should_Contain_Schema_For_Function_Classes()
        {
            var namingStrategy    = new DefaultNamingStrategy();
            var filter            = new RouteConstraintFilter();
            var acceptor          = new OpenApiSchemaAcceptor();
            var documentHelper    = new DocumentHelper(filter, acceptor);
            var visitorCollection = VisitorCollection.CreateInstance();

            var methods = typeof(FakeFunctions).GetMethods().ToList();

            var schemas = documentHelper.GetOpenApiSchemas(methods, namingStrategy, visitorCollection);

            schemas.Should().NotBeNull();
            schemas.Count.Should().Be(6);

            schemas.Should().ContainKey("FakeClassModel");

            schemas["FakeClassModel"].Properties.Count.Should().Be(2);
            schemas["FakeClassModel"].Type.Should().Be("object");

            schemas.Should().ContainKey("FakeOtherClassModel");

            schemas["FakeOtherClassModel"].Properties.Count.Should().Be(2);
            schemas["FakeOtherClassModel"].Type.Should().Be("object");

            schemas["FakeClassModel"].Properties.Count.Should().Be(2);
            schemas["FakeClassModel"].Type.Should().Be("object");

            schemas.Should().ContainKey("FakeListModel");

            schemas["FakeListModel"].Properties.Count.Should().Be(1);
            schemas["FakeListModel"].Type.Should().Be("object");

            schemas.Should().ContainKey("FakeStringModel");
            schemas["FakeStringModel"].Properties.Count.Should().Be(2);
            schemas["FakeStringModel"].Type.Should().Be("object");

            schemas.Should().ContainKey("FakeGenericModel_FakeClassModel");

            schemas["FakeGenericModel_FakeClassModel"].Properties.Count.Should().Be(2);
            schemas["FakeGenericModel_FakeClassModel"].Type.Should().Be("object");
            schemas["FakeGenericModel_FakeClassModel"].Properties.Should().ContainKey("Name");
            schemas["FakeGenericModel_FakeClassModel"].Properties.Should().ContainKey("Value");
            schemas["FakeGenericModel_FakeClassModel"].Properties["Value"].Properties.Should().ContainKey("Number");
            schemas["FakeGenericModel_FakeClassModel"].Properties["Value"].Properties.Should().ContainKey("Text");

            schemas.Should().ContainKey("FakeGenericModel_FakeOtherClassModel");

            schemas["FakeGenericModel_FakeOtherClassModel"].Properties.Count.Should().Be(2);
            schemas["FakeGenericModel_FakeOtherClassModel"].Type.Should().Be("object");
            schemas["FakeGenericModel_FakeOtherClassModel"].Properties.Should().ContainKey("Name");
            schemas["FakeGenericModel_FakeOtherClassModel"].Properties.Should().ContainKey("Value");
            schemas["FakeGenericModel_FakeOtherClassModel"].Properties["Value"].Properties.Should().ContainKey("FirstName");
            schemas["FakeGenericModel_FakeOtherClassModel"].Properties["Value"].Properties.Should().ContainKey("LastName");
        }
        /// <summary>
        /// Converts <see cref="OpenApiPayloadAttribute"/> to <see cref="OpenApiMediaType"/>.
        /// </summary>
        /// <typeparam name="T">Type of payload attribute inheriting <see cref="OpenApiPayloadAttribute"/>.</typeparam>
        /// <param name="attribute">OpenApi payload attribute.</param>
        /// <param name="namingStrategy"><see cref="NamingStrategy"/> instance to create the JSON schema from .NET Types.</param>
        /// <param name="collection"><see cref="VisitorCollection"/> instance.</param>
        /// <returns><see cref="OpenApiMediaType"/> instance.</returns>
        public static OpenApiMediaType ToOpenApiMediaType <T>(this T attribute, NamingStrategy namingStrategy = null, VisitorCollection collection = null) where T : OpenApiPayloadAttribute
        {
            attribute.ThrowIfNullOrDefault();

            if (namingStrategy.IsNullOrDefault())
            {
                namingStrategy = new DefaultNamingStrategy();
            }

            if (collection.IsNullOrDefault())
            {
                collection = VisitorCollection.CreateInstance();
            }

            var type = attribute.BodyType;

            // Generate schema based on the type.
            var schema = collection.PayloadVisit(type, namingStrategy);

            // Add deprecated attribute.
            if (attribute is OpenApiRequestBodyAttribute)
            {
                schema.Deprecated = (attribute as OpenApiRequestBodyAttribute).Deprecated;
            }
            if (attribute is OpenApiResponseWithBodyAttribute)
            {
                schema.Deprecated = (attribute as OpenApiResponseWithBodyAttribute).Deprecated;
            }

            // For array and dictionary object, the reference has already been added by the visitor.
            if (type.IsReferentialType() && !type.IsOpenApiNullable() && !type.IsOpenApiArray() && !type.IsOpenApiDictionary())
            {
                var reference = new OpenApiReference()
                {
                    Type = ReferenceType.Schema,
                    Id   = attribute.BodyType.GetOpenApiReferenceId(isDictionary: false, isList: false, namingStrategy)
                };

                schema.Reference = reference;
            }

            var mediaType = new OpenApiMediaType()
            {
                Schema = schema
            };

            return(mediaType);
        }
 public void Init()
 {
     this._visitorCollection = VisitorCollection.CreateInstance();
     this._visitor           = new DictionaryObjectTypeVisitor(this._visitorCollection);
     this._strategy          = new CamelCaseNamingStrategy();
 }
Example #4
0
        /// <inheritdoc />
        public virtual VisitorCollection GetVisitorCollection()
        {
            var collection = VisitorCollection.CreateInstance();

            return(collection);
        }
Example #5
0
        /// <summary>
        /// Generates the OpenAPI document.
        /// </summary>
        /// <param name="project">Project path.</param>
        /// <param name="configuration">Copile configuration.</param>
        /// <param name="version">OpenAPI version.</param>
        /// <param name="format">OpenAPI output format.</param>
        /// <param name="output">Output path.</param>
        /// <param name="console">Value indicating whether to render the document on console or not.</param>
        public void Generate(
            [Option('p', Description = "Project path. Default is current directory")] string project  = ".",
            [Option('c', Description = "Configuration. Default is 'Debug'")] string configuration     = "Debug",
            [Option('t', Description = "Target framework. Default is 'netcoreapp2.1'")] string target = "netcoreapp2.1",
            [Option('v', Description = "OpenAPI spec version. Value can be either 'v2' or 'v3'. Default is 'v2'")] OpenApiVersionType version      = OpenApiVersionType.V2,
            [Option('f', Description = "OpenAPI output format. Value can be either 'json' or 'yaml'. Default is 'yaml'")] OpenApiFormatType format = OpenApiFormatType.Json,
            [Option('o', Description = "Generated OpenAPI output location. Default is 'output'")] string output = "output",
            bool console = false)
        {
            var pi = default(ProjectInfo);

            try
            {
                pi = new ProjectInfo(project, configuration, target);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);

                return;
            }

            var req = new Mock <HttpRequest>();

            req.SetupGet(p => p.Scheme).Returns("http");
            req.SetupGet(p => p.Host).Returns(new HostString("localhost", 7071));

            var filter         = new RouteConstraintFilter();
            var acceptor       = new OpenApiSchemaAcceptor();
            var namingStrategy = new CamelCaseNamingStrategy();
            var collection     = VisitorCollection.CreateInstance();
            var helper         = new DocumentHelper(filter, acceptor);
            var document       = new Document(helper);

            var swagger = default(string);

            try
            {
                swagger = document.InitialiseDocument()
                          .AddMetadata(pi.OpenApiInfo)
                          .AddServer(req.Object, pi.HostJsonHttpSettings.RoutePrefix)
                          .AddNamingStrategy(namingStrategy)
                          .AddVisitors(collection)
                          .Build(pi.CompiledDllPath)
                          .RenderAsync(version.ToOpenApiSpecVersion(), format.ToOpenApiFormat())
                          .Result;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }

            if (console)
            {
                Console.WriteLine(swagger);
            }

            var outputpath = Path.IsPathFullyQualified(output)
                                 ? output
                                 : $"{pi.CompiledPath}{directorySeparator}{output}";

            if (!Directory.Exists(outputpath))
            {
                Directory.CreateDirectory(outputpath);
            }

            File.WriteAllText($"{outputpath}{directorySeparator}swagger.{format.ToDisplayName()}", swagger, Encoding.UTF8);
        }
Example #6
0
        /// <summary>
        /// Converts <see cref="OpenApiParameterAttribute"/> to <see cref="OpenApiParameter"/>.
        /// </summary>
        /// <param name="attribute"><see cref="OpenApiParameterAttribute"/> instance.</param>
        /// <param name="namingStrategy"><see cref="NamingStrategy"/> instance.</param>
        /// <param name="collection"><see cref="VisitorCollection"/> instance.</param>
        /// <returns><see cref="OpenApiParameter"/> instance.</returns>
        public static OpenApiParameter ToOpenApiParameter(this OpenApiParameterAttribute attribute, NamingStrategy namingStrategy = null, VisitorCollection collection = null)
        {
            attribute.ThrowIfNullOrDefault();

            if (namingStrategy.IsNullOrDefault())
            {
                namingStrategy = new DefaultNamingStrategy();
            }

            if (collection.IsNullOrDefault())
            {
                collection = VisitorCollection.CreateInstance();
            }

            var type = attribute.Type;

            var schema = collection.ParameterVisit(type, namingStrategy);

            var parameter = new OpenApiParameter()
            {
                Name        = attribute.Name,
                Description = attribute.Description,
                Required    = attribute.Required,
                In          = attribute.In,
                Schema      = schema
            };

            if (type.IsOpenApiArray())
            {
                if (attribute.In == ParameterLocation.Path)
                {
                    parameter.Style   = ParameterStyle.Simple;
                    parameter.Explode = false;
                }

                if (attribute.In == ParameterLocation.Query)
                {
                    parameter.Style = attribute.CollectionDelimiter == OpenApiParameterCollectionDelimiterType.Comma
                                      ? ParameterStyle.Form
                                      : (attribute.CollectionDelimiter == OpenApiParameterCollectionDelimiterType.Space
                                         ? ParameterStyle.SpaceDelimited
                                         : ParameterStyle.PipeDelimited);
                    parameter.Explode = attribute.CollectionDelimiter == OpenApiParameterCollectionDelimiterType.Comma
                                        ? attribute.Explode
                                        : false;
                }
            }

            if (!string.IsNullOrWhiteSpace(attribute.Summary))
            {
                var summary = new OpenApiString(attribute.Summary);

                parameter.Extensions.Add("x-ms-summary", summary);
            }

            if (attribute.Visibility != OpenApiVisibilityType.Undefined)
            {
                var visibility = new OpenApiString(attribute.Visibility.ToDisplayName());

                parameter.Extensions.Add("x-ms-visibility", visibility);
            }

            return(parameter);
        }
Example #7
0
        /// <summary>
        /// Converts <see cref="OpenApiPayloadAttribute"/> to <see cref="OpenApiMediaType"/>.
        /// </summary>
        /// <typeparam name="T">Type of payload attribute inheriting <see cref="OpenApiPayloadAttribute"/>.</typeparam>
        /// <param name="attribute">OpenApi payload attribute.</param>
        /// <param name="namingStrategy"><see cref="NamingStrategy"/> instance to create the JSON schema from .NET Types.</param>
        /// <param name="collection"><see cref="VisitorCollection"/> instance.</param>
        /// <param name="version">OpenAPI spec version.</param>
        /// <returns><see cref="OpenApiMediaType"/> instance.</returns>
        public static OpenApiMediaType ToOpenApiMediaType <T>(this T attribute, NamingStrategy namingStrategy = null, VisitorCollection collection = null, OpenApiVersionType version = OpenApiVersionType.V2) where T : OpenApiPayloadAttribute
        {
            attribute.ThrowIfNullOrDefault();

            if (namingStrategy.IsNullOrDefault())
            {
                namingStrategy = new DefaultNamingStrategy();
            }

            if (collection.IsNullOrDefault())
            {
                collection = VisitorCollection.CreateInstance();
            }

            var type = attribute.BodyType;

            // Generate schema based on the type.
            var schema = collection.PayloadVisit(type, namingStrategy);

            // Add deprecated attribute.
            if (attribute is OpenApiRequestBodyAttribute)
            {
                schema.Deprecated = (attribute as OpenApiRequestBodyAttribute).Deprecated;
            }
            if (attribute is OpenApiResponseWithBodyAttribute)
            {
                schema.Deprecated = (attribute as OpenApiResponseWithBodyAttribute).Deprecated;
            }

            // For array and dictionary object, the reference has already been added by the visitor.
            if (type.IsReferentialType() && !type.IsOpenApiNullable() && !type.IsOpenApiArray() && !type.IsOpenApiDictionary())
            {
                var reference = new OpenApiReference()
                {
                    Type = ReferenceType.Schema,
                    Id   = attribute.BodyType.GetOpenApiReferenceId(isDictionary: false, isList: false, namingStrategy)
                };

                schema.Reference = reference;
            }

            var mediaType = new OpenApiMediaType()
            {
                Schema = schema
            };

            if (attribute.Example.IsNullOrDefault())
            {
                return(mediaType);
            }

            if (!attribute.Example.HasInterface("IOpenApiExample`1"))
            {
                return(mediaType);
            }

            var example  = (dynamic)Activator.CreateInstance(attribute.Example);
            var examples = (IDictionary <string, OpenApiExample>)example.Build(namingStrategy).Examples;

            mediaType.Examples = examples;
            if (version == OpenApiVersionType.V2)
            {
                mediaType.Example = examples.First().Value.Value;
            }

            return(mediaType);
        }