Beispiel #1
0
        /// <summary>
        /// Creates an OpenAPI document from a CSDL document.
        /// </summary>
        /// <param name="uri">The file path of the CSDL document location.</param>
        /// <param name="styleOptions">Optional parameter that defines the style
        /// options to be used in formatting the OpenAPI document.</param>
        /// <returns></returns>
        public static OpenApiDocument CreateOpenApiDocument(string uri, OpenApiStyleOptions styleOptions = null)
        {
            if (string.IsNullOrEmpty(uri))
            {
                return(null);
            }

            using StreamReader streamReader = new StreamReader(uri);
            Stream csdl = streamReader.BaseStream;

            var edmModel = CsdlReader.Parse(XElement.Load(csdl).CreateReader());

            var settings = new OpenApiConvertSettings()
            {
                EnableKeyAsSegment            = true,
                EnableOperationId             = true,
                PrefixEntityTypeNameBeforeKey = true,
                TagDepth                 = 2,
                EnablePagination         = styleOptions != null && styleOptions.EnablePagination,
                EnableDiscriminatorValue = styleOptions != null && styleOptions.EnableDiscriminatorValue,
                EnableDerivedTypesReferencesForRequestBody = styleOptions != null && styleOptions.EnableDerivedTypesReferencesForRequestBody,
                EnableDerivedTypesReferencesForResponses   = styleOptions != null && styleOptions.EnableDerivedTypesReferencesForResponses,
                ShowRootPath = styleOptions != null && styleOptions.ShowRootPath
            };
            OpenApiDocument document = edmModel.ConvertToOpenApi(settings);

            document = FixReferences(document);

            return(document);
        }
        public void GetTypeCastPathsForModelWithDerivedTypesConstraint(
            bool addAnnotation,
            bool getNavPropModel,
            bool requireConstraint,
            bool appendBoundOperationsOnDerivedTypes,
            int expectedCount)
        {
            // Arrange
            var               annotation = addAnnotation ? derivedTypeAnnotation : string.Empty;
            IEdmModel         model      = getNavPropModel ? GetNavPropModel(annotation) : GetInheritanceModel(annotation);
            ODataPathProvider provider   = new();
            var               settings   = new OpenApiConvertSettings
            {
                RequireDerivedTypesConstraintForODataTypeCastSegments = requireConstraint,
                AppendBoundOperationsOnDerivedTypeCastSegments        = appendBoundOperationsOnDerivedTypes
            };

            // Act
            var paths = provider.GetPaths(model, settings);

            // Assert
            Assert.NotNull(paths);
            Assert.Equal(expectedCount, paths.Count());
            var dollarCountPathsWithCastSegment = paths.Where(x => x.Kind == ODataPathKind.DollarCount && x.Any(y => y.Kind == ODataSegmentKind.TypeCast));

            if (addAnnotation || !requireConstraint)
            {
                Assert.Single(dollarCountPathsWithCastSegment);
            }
            else
            {
                Assert.Empty(dollarCountPathsWithCastSegment);
            }
        }
        public void CreateEdmTypeSchemaReturnSchemaForInt64(bool isNullable, bool IEEE754Compatible)
        {
            // Arrange
            IEdmModel model = EdmCoreModel.Instance;
            OpenApiConvertSettings settings = new OpenApiConvertSettings
            {
                IEEE754Compatible = IEEE754Compatible
            };

            ODataContext      context          = new ODataContext(model, settings);
            IEdmTypeReference edmTypeReference = EdmCoreModel.Instance.GetInt64(isNullable);

            // Act
            var schema = context.CreateEdmTypeSchema(edmTypeReference);

            Assert.NotNull(schema); // guard

            // & Assert
            if (IEEE754Compatible)
            {
                Assert.Null(schema.Type);
                Assert.NotNull(schema.AnyOf);
                Assert.Equal(2, schema.AnyOf.Count);
                Assert.Equal(new[] { "integer", "string" }, schema.AnyOf.Select(a => a.Type));
            }
            else
            {
                Assert.Equal("integer", schema.Type);
                Assert.Null(schema.AnyOf);
            }

            Assert.Equal(isNullable, schema.Nullable);
        }
        private string FunctionImportName(IEdmFunctionImport functionImport, OpenApiConvertSettings settings)
        {
            StringBuilder functionName = new StringBuilder(functionImport.Name);

            functionName.Append("(");

            // Structured or collection-valued parameters are represented as a parameter alias in the path template
            // and the parameters array contains a Parameter Object for the parameter alias as a query option of type string.
            IEdmFunction function = functionImport.Function;

            functionName.Append(String.Join(",", function.Parameters.Select(p =>
            {
                if (p.Type.IsStructured() || p.Type.IsCollection())
                {
                    return(p.Name + "=@" + p.Name);
                }
                else
                {
                    return(p.Name + "={" + p.Name + "}");
                }
            })));

            functionName.Append(")");
            return(functionName.ToString());
        }
        public void GetPathsWithBoundFunctionOperationForContainmentNavigationPropertyPathsWorks(bool containsTarget)
        {
            // Arrange
            string navProp     = $@"<NavigationProperty Name=""Referral"" Type=""NS.NiceCustomer"" ContainsTarget=""{containsTarget}""/>";
            string boundAction =
                @"<Function Name=""Search"" IsBound=""true"">
   <Parameter Name=""bindingParameter"" Type=""NS.NiceCustomer"" />
     <ReturnType Type=""Collection(NS.Customer)"" />
</Function>
<EntityType Name=""NiceCustomer"">
    <Property Name=""Other"" Type=""Edm.Int32"" Nullable=""true"" />
</EntityType>";

            IEdmModel         model    = GetEdmModel(boundAction, "", navProp);
            ODataPathProvider provider = new ODataPathProvider();
            var settings = new OpenApiConvertSettings();

            // Act
            var paths = provider.GetPaths(model, settings);

            // Assert
            Assert.NotNull(paths);

            if (containsTarget)
            {
                Assert.Equal(5, paths.Count());
                Assert.Contains("/Customers({ID})/Referral/NS.Search()", paths.Select(p => p.GetPathItemName()));
            }
            else
            {
                Assert.Equal(4, paths.Count());
                Assert.DoesNotContain("/Customers({ID})/Referral/NS.Search()", paths.Select(p => p.GetPathItemName()));
            }
        }
Beispiel #6
0
        /// <summary>
        /// Gets the path item name.
        /// </summary>
        /// <param name="settings">The settings.</param>
        /// <returns>The string.</returns>
        public string GetPathItemName(OpenApiConvertSettings settings)
        {
            Utils.CheckArgumentNull(settings, nameof(settings));

            StringBuilder sb = new StringBuilder();

            foreach (var segment in Segments)
            {
                string pathItemName = segment.GetPathItemName(settings);

                if (segment.Kind == ODataSegmentKind.Key &&
                    (settings.EnableKeyAsSegment == null || !settings.EnableKeyAsSegment.Value))
                {
                    sb.Append("(");
                    sb.Append(pathItemName);
                    sb.Append(")");
                }
                else // other segments
                {
                    sb.Append("/");
                    sb.Append(pathItemName);
                }
            }

            return(sb.ToString());
        }
        public void BasicEdmModelToOpenApiJsonWorks(OpenApiSpecVersion specVersion)
        {
            // Arrange
            IEdmModel model = EdmModelHelper.BasicEdmModel;
            var       openApiConvertSettings = new OpenApiConvertSettings
            {
                OpenApiSpecVersion = specVersion,
                ShowSchemaExamples = true // test for schema examples
            };

            // Act
            string json = WriteEdmModelAsOpenApi(model, OpenApiFormat.Json, openApiConvertSettings);

            _output.WriteLine(json);

            // Assert
            if (specVersion == OpenApiSpecVersion.OpenApi2_0)
            {
                Assert.Equal(Resources.GetString("Basic.OpenApi.V2.json").ChangeLineBreaks(), json);
            }
            else
            {
                Assert.Equal(Resources.GetString("Basic.OpenApi.json").ChangeLineBreaks(), json);
            }
        }
        internal IDictionary <string, string> GetKeyNameMapping(OpenApiConvertSettings settings, HashSet <string> parameters)
        {
            IDictionary <string, string>   keyNamesMapping = new Dictionary <string, string>();
            IList <IEdmStructuralProperty> keys            = EntityType.Key().ToList();

            if (keys.Count() == 1)
            {
                string keyName = keys.First().Name;

                if (settings.PrefixEntityTypeNameBeforeKey)
                {
                    string name = Utils.GetUniqueName(EntityType.Name + "-" + keyName, parameters);
                    keyNamesMapping[keyName] = name;
                }
                else
                {
                    string name = Utils.GetUniqueName(keyName, parameters);
                    keyNamesMapping[keyName] = name;
                }
            }
            else
            {
                foreach (var keyProperty in keys)
                {
                    string name = Utils.GetUniqueName(keyProperty.Name, parameters);
                    keyNamesMapping[keyProperty.Name] = name;
                }
            }

            return(keyNamesMapping);
        }
        public void MultipleSchemasEdmModelToOpenApiYamlWorks(OpenApiSpecVersion specVersion)
        {
            // Arrange
            IEdmModel model = EdmModelHelper.MultipleSchemasEdmModel;
            var       openApiConvertSettings = new OpenApiConvertSettings
            {
                OpenApiSpecVersion = specVersion,
                ShowLinks          = true, // test Links
                ShowSchemaExamples = true
            };

            // Act
            string yaml = WriteEdmModelAsOpenApi(model, OpenApiFormat.Yaml, openApiConvertSettings);

            _output.WriteLine(yaml);

            // Assert
            if (specVersion == OpenApiSpecVersion.OpenApi2_0)
            {
                Assert.Equal(Resources.GetString("Multiple.Schema.OpenApi.V2.yaml").ChangeLineBreaks(), yaml);
            }
            else
            {
                Assert.Equal(Resources.GetString("Multiple.Schema.OpenApi.yaml").ChangeLineBreaks(), yaml);
            }
        }
        /// <summary>
        /// Initializes a new instance of <see cref="ODataContext"/> class.
        /// </summary>
        /// <param name="model">The Edm model.</param>
        /// <param name="settings">The convert setting.</param>
        public ODataContext(IEdmModel model, OpenApiConvertSettings settings)
        {
            Model    = model ?? throw Error.ArgumentNull(nameof(model));
            Settings = settings ?? throw Error.ArgumentNull(nameof(settings));

            EdmSpatialTypeVisitor visitor = new EdmSpatialTypeVisitor();

            visitor.Visit(model);
            IsSpatialTypeUsed = visitor.IsSpatialTypeUsed;

            OperationHanderProvider = new OperationHandlerProvider();
            PathItemHanderProvider  = new PathItemHandlerProvider();

            _pathProvider = new ODataPathProvider();

            if (settings.EnableKeyAsSegment != null)
            {
                // We have the global setting, use the global setting
                KeyAsSegment = settings.EnableKeyAsSegment.Value;
            }
            else
            {
                KeyAsSegment = false;
                if (model.EntityContainer != null)
                {
                    var keyAsSegment = model.GetBoolean(model.EntityContainer, CapabilitiesConstants.KeyAsSegmentSupported);
                    if (keyAsSegment != null)
                    {
                        KeyAsSegment = keyAsSegment.Value;
                    }
                }
            }
        }
Beispiel #11
0
        /// <summary>
        /// Create a map of <see cref="OpenApiPathItem"/>.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <returns>The created map of <see cref="OpenApiPathItem"/>.</returns>
        public static IDictionary <string, OpenApiPathItem> CreatePathItems(this ODataContext context)
        {
            Utils.CheckArgumentNull(context, nameof(context));

            IDictionary <string, OpenApiPathItem> pathItems = new Dictionary <string, OpenApiPathItem>();

            if (context.EntityContainer == null)
            {
                return(pathItems);
            }

            OpenApiConvertSettings settings = context.Settings.Clone();

            settings.EnableKeyAsSegment = context.KeyAsSegment;
            foreach (ODataPath path in context.AllPaths)
            {
                IPathItemHandler handler = context.PathItemHanderProvider.GetHandler(path.Kind);
                if (handler == null)
                {
                    continue;
                }

                pathItems.Add(path.GetPathItemName(settings), handler.CreatePathItem(context, path));
            }

            return(pathItems);
        }
Beispiel #12
0
        /// <summary>
        /// Generate the Open Api.
        /// </summary>
        public bool Generate()
        {
            try
            {
                IEdmModel edmModel = GetEdmModel();

                OpenApiConvertSettings settings = GetSettings();

                settings.OpenApiSpecVersion = Version;

                using (FileStream fs = File.Create(Output))
                {
                    OpenApiDocument document = edmModel.ConvertToOpenApi(settings);
                    document.Serialize(fs, settings.OpenApiSpecVersion, Format);
                    fs.Flush();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return(false);
            }

            return(true);
        }
Beispiel #13
0
        public void CreateResponseForEdmActionWhenErrorResponsesAsDefaultIsSet(string actionName, bool errorAsDefault, string responseCode)
        {
            // Arrange
            IEdmModel model    = EdmModelHelper.GraphBetaModel;
            var       settings = new OpenApiConvertSettings
            {
                ErrorResponsesAsDefault = errorAsDefault,
            };
            ODataContext context = new ODataContext(model, settings);

            // Act
            OpenApiResponses responses;
            IEdmOperation    operation = model.SchemaElements.OfType <IEdmOperation>().First(o => o.Name == actionName);

            Assert.NotNull(operation); // guard
            ODataPath path = new(new ODataOperationSegment(operation));

            responses = context.CreateResponses(operation, path);

            // Assert
            Assert.NotNull(responses);
            Assert.NotEmpty(responses);
            if (errorAsDefault)
            {
                Assert.Equal(new string[] { responseCode, "default" }, responses.Select(r => r.Key));
            }
            else
            {
                Assert.Equal(new string[] { responseCode, "4XX", "5XX" }, responses.Select(r => r.Key));
            }
        }
        public void GetPathsWithStreamPropertyAndWithEntityHasStreamWorks(bool hasStream, string streamPropName)
        {
            // Arrange
            IEdmModel         model    = GetEdmModel(hasStream, streamPropName);
            ODataPathProvider provider = new ODataPathProvider();
            var settings = new OpenApiConvertSettings();

            // Act
            var paths = provider.GetPaths(model, settings);

            // Assert
            Assert.NotNull(paths);

            if (hasStream && !streamPropName.Equals("Content", StringComparison.OrdinalIgnoreCase))
            {
                Assert.Equal(7, paths.Count());
                Assert.Equal(new[] { "/me", "/me/photo", "/me/photo/$value", "/Todos", "/Todos({Id})", "/Todos({Id})/$value", "/Todos({Id})/Logo" },
                             paths.Select(p => p.GetPathItemName()));
            }
            else if ((hasStream && streamPropName.Equals("Content", StringComparison.OrdinalIgnoreCase)) ||
                     (!hasStream && streamPropName.Equals("Content", StringComparison.OrdinalIgnoreCase)))
            {
                Assert.Equal(6, paths.Count());
                Assert.Equal(new[] { "/me", "/me/photo", "/me/photo/$value", "/Todos", "/Todos({Id})", "/Todos({Id})/Content" },
                             paths.Select(p => p.GetPathItemName()));
            }
            else // !hasStream && !streamPropName.Equals("Content")
            {
                Assert.Equal(6, paths.Count());
                Assert.Equal(new[] { "/me", "/me/photo", "/me/photo/$value", "/Todos", "/Todos({Id})", "/Todos({Id})/Logo" },
                             paths.Select(p => p.GetPathItemName()));
            }
        }
Beispiel #15
0
        /// <summary>
        /// Converts CSDL to OpenAPI
        /// </summary>
        /// <param name="csdl">The CSDL stream.</param>
        /// <returns>An OpenAPI document.</returns>
        public static async Task <OpenApiDocument> ConvertCsdlToOpenApiAsync(Stream csdl)
        {
            using var reader = new StreamReader(csdl);
            var csdlTxt = await reader.ReadToEndAsync();

            var edmModel = CsdlReader.Parse(XElement.Parse(csdlTxt).CreateReader());

            var settings = new OpenApiConvertSettings()
            {
                EnableKeyAsSegment            = true,
                EnableOperationId             = true,
                PrefixEntityTypeNameBeforeKey = true,
                TagDepth                 = 2,
                EnablePagination         = true,
                EnableDiscriminatorValue = false,
                EnableDerivedTypesReferencesForRequestBody = false,
                EnableDerivedTypesReferencesForResponses   = false,
                ShowRootPath = true,
                ShowLinks    = true
            };
            OpenApiDocument document = edmModel.ConvertToOpenApi(settings);

            document = FixReferences(document);
            return(document);
        }
        public void GetPathsWithUnboundOperationImportWorks()
        {
            // Arrange
            string boundAction =
                @"<Function Name=""GetNearestCustomers"">
   <ReturnType Type=""NS.Customer"" />
  </Function >
  <Action Name=""ResetDataSource"" />";

            string    unbounds = @"
<FunctionImport Name=""GetNearestCustomers"" Function=""NS.GetNearestCustomers"" EntitySet=""Customers"" />
<ActionImport Name =""ResetDataSource"" Action =""NS.ResetDataSource"" />";
            IEdmModel model    = GetEdmModel(boundAction, unbounds);

            ODataPathProvider provider = new ODataPathProvider();
            var settings = new OpenApiConvertSettings();

            // Act
            var paths = provider.GetPaths(model, settings);

            // Assert
            Assert.NotNull(paths);
            Assert.Equal(4, paths.Count());
            Assert.Contains("/GetNearestCustomers()", paths.Select(p => p.GetPathItemName()));
            Assert.Contains("/ResetDataSource", paths.Select(p => p.GetPathItemName()));
        }
        public void GetPathsWithContainedNavigationPropertytWorks()
        {
            // Arrange
            string entityType =
                @"<EntityType Name=""Order"">
    <Key>
      <PropertyRef Name=""id"" />
    </Key>
    <NavigationProperty Name=""MultipleCustomers"" Type=""Collection(NS.Customer)"" ContainsTarget=""true"" />
    <NavigationProperty Name=""SingleCustomer"" Type=""NS.Customer"" ContainsTarget=""true"" />
  </EntityType>";

            string            entitySet = @"<EntitySet Name=""Orders"" EntityType=""NS.Order"" />";
            IEdmModel         model     = GetEdmModel(entityType, entitySet);
            ODataPathProvider provider  = new ODataPathProvider();
            var settings = new OpenApiConvertSettings();

            // Act
            var paths = provider.GetPaths(model, settings);

            // Assert
            Assert.NotNull(paths);
            Assert.Equal(7, paths.Count());

            var pathItems = paths.Select(p => p.GetPathItemName()).ToList();

            Assert.Contains("/Orders({id})/MultipleCustomers", pathItems);
            Assert.Contains("/Orders({id})/MultipleCustomers({ID})", pathItems);
            Assert.Contains("/Orders({id})/SingleCustomer", pathItems);
        }
Beispiel #18
0
        static int Main(string[] args)
        {
            // we assume the path are existed for simplicity.
            string path  = Directory.GetCurrentDirectory();
            string csdl  = path + "/../../../../../docs/csdl";
            string oas20 = path + "/../../../../../docs/oas_2_0";
            string oas30 = path + "/../../../../../docs/oas3_0_0";

            foreach (var filePath in Directory.GetFiles(csdl, "*.xml"))
            {
                IEdmModel model = LoadEdmModel(filePath);
                if (model == null)
                {
                    continue;
                }

                FileInfo fileInfo = new FileInfo(filePath);
                string   fileName = fileInfo.Name.Substring(0, fileInfo.Name.Length - 4);

                OpenApiConvertSettings settings = new OpenApiConvertSettings();
                if (fileName.Contains("graph.beta"))
                {
                    settings.PrefixEntityTypeNameBeforeKey = true;
                    settings.ServiceRoot = new Uri("https://graph.microsoft.com/beta");
                }
                else if (fileName.Contains("graph1.0"))
                {
                    settings.PrefixEntityTypeNameBeforeKey = true;
                    settings.ServiceRoot = new Uri("https://graph.microsoft.com/v1.0");
                }

                OpenApiDocument document = model.ConvertToOpenApi(settings);

                string output;/* = oas20 + "/" + fileName + ".yaml";
                               * File.WriteAllText(output, document.SerializeAsYaml(OpenApiSpecVersion.OpenApi2_0));
                               *
                               * output = oas20 + "/" + fileName + ".json";
                               * File.WriteAllText(output, document.SerializeAsJson(OpenApiSpecVersion.OpenApi2_0));
                               *
                               * output = oas30 + "/" + fileName + ".yaml";
                               * File.WriteAllText(output, document.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0));
                               *
                               * output = oas30 + "/" + fileName + ".json";
                               * File.WriteAllText(output, document.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0));
                               */
                settings.EnableKeyAsSegment    = true;
                settings.EnableUnqualifiedCall = true;
                output   = oas30 + "/" + fileName + ".json";
                document = model.ConvertToOpenApi(settings);
                File.WriteAllText(output, document.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0));

                output = oas20 + "/" + fileName + ".json";
                File.WriteAllText(output, document.SerializeAsJson(OpenApiSpecVersion.OpenApi2_0));

                Console.WriteLine("Output [ " + fileName + " ] Succeessful!");
            }

            Console.WriteLine("\n==> All Done!");
            return(0);
        }
Beispiel #19
0
        /// <inheritdoc />
        public override string GetPathItemName(OpenApiConvertSettings settings, HashSet <string> parameters)
        {
            Utils.CheckArgumentNull(settings, nameof(settings));

            IList <IEdmStructuralProperty> keys = EntityType.Key().ToList();

            if (keys.Count() == 1)
            {
                string keyName = keys.First().Name;

                if (settings.PrefixEntityTypeNameBeforeKey)
                {
                    string name = Utils.GetUniqueName(EntityType.Name + "-" + keyName, parameters);
                    return("{" + name + "}");
                }
                else
                {
                    string name = Utils.GetUniqueName(keyName, parameters);
                    return("{" + name + "}");
                }
            }
            else
            {
                IList <string> keyStrings = new List <string>();
                foreach (var keyProperty in keys)
                {
                    string name = Utils.GetUniqueName(keyProperty.Name, parameters);
                    keyStrings.Add(keyProperty.Name + "={" + name + "}");
                }

                return(String.Join(",", keyStrings));
            }
        }
        /// <summary>
        /// Create a map of <see cref="OpenApiPathItem"/>.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <returns>The created map of <see cref="OpenApiPathItem"/>.</returns>
        public static IDictionary <string, OpenApiPathItem> CreatePathItems(this ODataContext context)
        {
            Utils.CheckArgumentNull(context, nameof(context));

            IDictionary <string, OpenApiPathItem> pathItems = new Dictionary <string, OpenApiPathItem>();

            if (context.EntityContainer == null)
            {
                return(pathItems);
            }

            OpenApiConvertSettings settings = context.Settings.Clone();

            settings.EnableKeyAsSegment = context.KeyAsSegment;
            foreach (ODataPath path in context.AllPaths)
            {
                try
                {
                    IPathItemHandler handler = context.PathItemHanderProvider.GetHandler(path.Kind);
                    if (handler == null)
                    {
                        continue;
                    }

                    pathItems.Add(path.GetPathItemName(settings), handler.CreatePathItem(context, path));
                }catch (Exception ex)
                {
                    System.Diagnostics.Trace.WriteLine("Error generating path:" + ex.Message);
                }
            }

            return(pathItems);
        }
Beispiel #21
0
        private string FunctionName(IEdmFunction function, OpenApiConvertSettings settings)
        {
            StringBuilder functionName = new StringBuilder();

            if (settings.EnableUnqualifiedCall)
            {
                functionName.Append(function.Name);
            }
            else
            {
                functionName.Append(function.FullName());
            }
            functionName.Append("(");

            // Structured or collection-valued parameters are represented as a parameter alias in the path template
            // and the parameters array contains a Parameter Object for the parameter alias as a query option of type string.
            int skip = function.IsBound ? 1 : 0;

            functionName.Append(String.Join(",", function.Parameters.Skip(skip).Select(p =>
            {
                if (p.Type.IsStructured() || p.Type.IsCollection())
                {
                    return(p.Name + "=@" + p.Name);
                }
                else
                {
                    return(p.Name + "={" + p.Name + "}");
                }
            })));

            functionName.Append(")");

            return(functionName.ToString());
        }
        public void TripServiceMetadataToOpenApiYamlWorks(OpenApiSpecVersion specVersion)
        {
            // Arrange
            IEdmModel model = EdmModelHelper.TripServiceModel;

            OpenApiConvertSettings settings = new OpenApiConvertSettings
            {
                EnableKeyAsSegment = true,
                Version            = new Version(1, 0, 1),
                ServiceRoot        = new Uri("http://services.odata.org/TrippinRESTierService"),
                IEEE754Compatible  = true,
                OpenApiSpecVersion = specVersion
            };

            // Act
            string yaml = WriteEdmModelAsOpenApi(model, OpenApiFormat.Yaml, settings);

            _output.WriteLine(yaml);

            // Assert
            if (specVersion == OpenApiSpecVersion.OpenApi2_0)
            {
                Assert.Equal(Resources.GetString("TripService.OpenApi.V2.yaml").ChangeLineBreaks(), yaml);
            }
            else
            {
                Assert.Equal(Resources.GetString("TripService.OpenApi.yaml").ChangeLineBreaks(), yaml);
            }
        }
        private OpenApiDocument CreateDocument(string prefixName)
        {
            IDictionary <string, ODataPath> tempateToPathDict = new Dictionary <string, ODataPath>();
            ODataOpenApiPathProvider        provider          = new ODataOpenApiPathProvider();
            IEdmModel model = null;

            foreach (var endpoint in _dataSource.Endpoints)
            {
                IODataRoutingMetadata metadata = endpoint.Metadata.GetMetadata <IODataRoutingMetadata>();
                if (metadata == null)
                {
                    continue;
                }

                if (metadata.Prefix != prefixName)
                {
                    continue;
                }
                model = metadata.Model;

                RouteEndpoint routeEndpoint = endpoint as RouteEndpoint;
                if (routeEndpoint == null)
                {
                    continue;
                }

                // get rid of the prefix
                int    length            = prefixName.Length;
                string routePathTemplate = routeEndpoint.RoutePattern.RawText.Substring(length);
                routePathTemplate = routePathTemplate.StartsWith("/") ? routePathTemplate : "/" + routePathTemplate;

                if (tempateToPathDict.TryGetValue(routePathTemplate, out ODataPath pathValue))
                {
                    string method = GetHttpMethod(metadata, endpoint);
                    pathValue.HttpMethods.Add(method);
                    continue;
                }

                var path = metadata.Template.Translate();
                if (path == null)
                {
                    continue;
                }

                path.PathTemplate = routePathTemplate;
                provider.Add(path);

                string method1 = GetHttpMethod(metadata, endpoint);
                path.HttpMethods.Add(method1);
                tempateToPathDict[routePathTemplate] = path;
            }

            OpenApiConvertSettings settings = new OpenApiConvertSettings
            {
                PathProvider = provider,
                ServiceRoot  = BuildAbsolute()
            };

            return(model.ConvertToOpenApi(settings));
        }
        public void CreatePathsReturnsForBasicModelWithPrefix()
        {
            // Arrange
            IEdmModel model = EdmModelHelper.BasicEdmModel;
            OpenApiConvertSettings settings = new OpenApiConvertSettings
            {
                EnableKeyAsSegment = true,
                PathPrefix         = "some/prefix"
            };
            ODataContext context = new ODataContext(model, settings);

            // Act
            var paths = context.CreatePaths();

            // Assert
            Assert.NotNull(paths);
            Assert.Equal(7, paths.Count);

            Assert.Contains("/some/prefix/People", paths.Keys);
            Assert.Contains("/some/prefix/People/{UserName}", paths.Keys);
            Assert.Contains("/some/prefix/City", paths.Keys);
            Assert.Contains("/some/prefix/City/{Name}", paths.Keys);
            Assert.Contains("/some/prefix/CountryOrRegion", paths.Keys);
            Assert.Contains("/some/prefix/CountryOrRegion/{Name}", paths.Keys);
            Assert.Contains("/some/prefix/Me", paths.Keys);
        }
Beispiel #25
0
        public void TripServiceMetadataToOpenApiJsonWorks(OpenApiSpecVersion specVersion)
        {
            // Arrange
            IEdmModel model = EdmModelHelper.TripServiceModel;
            OpenApiConvertSettings settings = new OpenApiConvertSettings
            {
                EnableKeyAsSegment = true,
                Version            = new Version(1, 0, 1),
                ServiceRoot        = new Uri("http://services.odata.org/TrippinRESTierService"),
                IEEE754Compatible  = true,
                OpenApiSpecVersion = specVersion,
                AddSingleQuotesForStringParameters             = true,
                AddEnumDescriptionExtension                    = true,
                AppendBoundOperationsOnDerivedTypeCastSegments = true
            };
            // Act
            string json = WriteEdmModelAsOpenApi(model, OpenApiFormat.Json, settings);

            _output.WriteLine(json);

            // Assert
            if (specVersion == OpenApiSpecVersion.OpenApi2_0)
            {
                Assert.Equal(Resources.GetString("TripService.OpenApi.V2.json").ChangeLineBreaks(), json);
            }
            else
            {
                Assert.Equal(Resources.GetString("TripService.OpenApi.json").ChangeLineBreaks(), json);
            }
        }
        public void CreateNavigationPatchOperationReturnsCorrectOperation(bool enableOperationId, bool useHTTPStatusCodeClass2XX)
        {
            // Arrange
            IEdmModel model = EdmModelHelper.TripServiceModel;
            OpenApiConvertSettings settings = new OpenApiConvertSettings
            {
                EnableOperationId         = enableOperationId,
                UseSuccessStatusCodeRange = useHTTPStatusCodeClass2XX
            };
            ODataContext  context = new ODataContext(model, settings);
            IEdmEntitySet people  = model.EntityContainer.FindEntitySet("People");

            Assert.NotNull(people);

            IEdmEntityType         person      = model.SchemaElements.OfType <IEdmEntityType>().First(c => c.Name == "Person");
            IEdmNavigationProperty navProperty = person.DeclaredNavigationProperties().First(c => c.Name == "BestFriend");
            ODataPath path = new ODataPath(new ODataNavigationSourceSegment(people), new ODataKeySegment(people.EntityType()), new ODataNavigationPropertySegment(navProperty));

            // Act
            var operation = _operationHandler.CreateOperation(context, path);

            // Assert
            Assert.NotNull(operation);
            Assert.Equal("Update the best friend.", operation.Summary);
            Assert.Equal("Update an instance of a best friend.", operation.Description);
            Assert.NotNull(operation.Tags);
            var tag = Assert.Single(operation.Tags);

            Assert.Equal("People.Person", tag.Name);

            Assert.NotNull(operation.Parameters);
            Assert.Equal(1, operation.Parameters.Count);

            Assert.NotNull(operation.RequestBody);
            Assert.Equal("New navigation property values", operation.RequestBody.Description);

            Assert.Equal(2, operation.Responses.Count);
            var statusCode = useHTTPStatusCodeClass2XX ? "2XX" : "204";

            Assert.Equal(new string[] { statusCode, "default" }, operation.Responses.Select(e => e.Key));

            if (useHTTPStatusCodeClass2XX)
            {
                Assert.Single(operation.Responses[statusCode].Content);
            }
            else
            {
                Assert.Empty(operation.Responses[statusCode].Content);
            }

            if (enableOperationId)
            {
                Assert.Equal("People.UpdateBestFriend", operation.OperationId);
            }
            else
            {
                Assert.Null(operation.OperationId);
            }
        }
        public void CreateSingletonPatchOperationReturnsCorrectOperation(bool enableOperationId, bool useHTTPStatusCodeClass2XX)
        {
            // Arrange
            string                 annotation = @"
        <Annotation Term=""Org.OData.Capabilities.V1.UpdateRestrictions"">
          <Record>
            <PropertyValue Property=""Description"" String=""Update the signed-in user."" />            
            <PropertyValue Property=""LongDescription"" String=""Update the signed-in user."" />            
          </Record>
        </Annotation>";
            IEdmModel              model      = SingletonGetOperationHandlerTests.GetEdmModel(annotation);
            IEdmSingleton          singleton  = model.EntityContainer.FindSingleton("Me");
            OpenApiConvertSettings settings   = new OpenApiConvertSettings
            {
                EnableOperationId         = enableOperationId,
                UseSuccessStatusCodeRange = useHTTPStatusCodeClass2XX
            };
            ODataContext context = new ODataContext(model, settings);
            ODataPath    path    = new ODataPath(new ODataNavigationSourceSegment(singleton));

            // Act
            var patch = _operationHandler.CreateOperation(context, path);

            // Assert
            Assert.NotNull(patch);
            Assert.Equal("Update the signed-in user.", patch.Summary);
            Assert.Equal("Update the signed-in user.", patch.Description);
            Assert.NotNull(patch.Tags);
            var tag = Assert.Single(patch.Tags);

            Assert.Equal("Me.Customer", tag.Name);

            Assert.Empty(patch.Parameters);
            Assert.NotNull(patch.RequestBody);

            Assert.NotNull(patch.Responses);
            Assert.Equal(2, patch.Responses.Count);
            var statusCode = useHTTPStatusCodeClass2XX ? "2XX" : "204";

            Assert.Equal(new[] { statusCode, "default" }, patch.Responses.Select(r => r.Key));

            if (useHTTPStatusCodeClass2XX)
            {
                Assert.Single(patch.Responses[statusCode].Content);
            }
            else
            {
                Assert.Empty(patch.Responses[statusCode].Content);
            }

            if (enableOperationId)
            {
                Assert.Equal("Me.Customer.UpdateCustomer", patch.OperationId);
            }
            else
            {
                Assert.Null(patch.OperationId);
            }
        }
        private bool AppendBoundOperationOnDerived(
            IEdmOperation edmOperation,
            bool isCollection,
            IEdmEntityType bindingEntityType,
            OpenApiConvertSettings convertSettings)
        {
            bool found = false;

            bool isEscapedFunction = _model.IsUrlEscapeFunction(edmOperation);

            foreach (var baseType in bindingEntityType.FindAllBaseTypes())
            {
                if (_allNavigationSources.TryGetValue(baseType, out IList <IEdmNavigationSource> baseNavigationSource))
                {
                    foreach (var ns in baseNavigationSource)
                    {
                        if (HasUnsatisfiedDerivedTypeConstraint(
                                ns as IEdmVocabularyAnnotatable,
                                baseType,
                                convertSettings))
                        {
                            continue;
                        }

                        if (isCollection)
                        {
                            if (ns is IEdmEntitySet)
                            {
                                ODataPath newPath = new ODataPath(new ODataNavigationSourceSegment(ns), new ODataTypeCastSegment(bindingEntityType),
                                                                  new ODataOperationSegment(edmOperation, isEscapedFunction));
                                AppendPath(newPath);
                                found = true;
                            }
                        }
                        else
                        {
                            if (ns is IEdmSingleton)
                            {
                                ODataPath newPath = new ODataPath(new ODataNavigationSourceSegment(ns), new ODataTypeCastSegment(bindingEntityType),
                                                                  new ODataOperationSegment(edmOperation, isEscapedFunction));
                                AppendPath(newPath);
                                found = true;
                            }
                            else
                            {
                                ODataPath newPath = new ODataPath(new ODataNavigationSourceSegment(ns), new ODataKeySegment(ns.EntityType()),
                                                                  new ODataTypeCastSegment(bindingEntityType),
                                                                  new ODataOperationSegment(edmOperation, isEscapedFunction));
                                AppendPath(newPath);
                                found = true;
                            }
                        }
                    }
                }
            }

            return(found);
        }
 private bool HasUnsatisfiedDerivedTypeConstraint(
     IEdmVocabularyAnnotatable annotatable,
     IEdmEntityType baseType,
     OpenApiConvertSettings convertSettings)
 {
     return(convertSettings.RequireDerivedTypesConstraintForBoundOperations &&
            !(_model.GetCollection(annotatable, "Org.OData.Validation.V1.DerivedTypeConstraint") ?? Enumerable.Empty <string>())
            .Any(c => c.Equals(baseType.FullName(), StringComparison.OrdinalIgnoreCase)));
 }
Beispiel #30
0
        /// <summary>
        /// Create a map of <see cref="OpenApiPathItem"/>.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <returns>The created map of <see cref="OpenApiPathItem"/>.</returns>
        public static IDictionary <string, OpenApiPathItem> CreatePathItems(this ODataContext context)
        {
            Utils.CheckArgumentNull(context, nameof(context));

            IDictionary <string, OpenApiPathItem> pathItems = new Dictionary <string, OpenApiPathItem>();

            if (context.EntityContainer == null)
            {
                return(pathItems);
            }

            OpenApiConvertSettings settings = context.Settings.Clone();

            settings.EnableKeyAsSegment = context.KeyAsSegment;
            foreach (ODataPath path in context.AllPaths)
            {
                IPathItemHandler handler = context.PathItemHanderProvider.GetHandler(path.Kind);
                if (handler == null)
                {
                    continue;
                }

                if (path.PathTemplate != null)
                {
                    pathItems.Add(path.PathTemplate, handler.CreatePathItem(context, path));
                }
                else
                {
                    pathItems.Add(path.GetPathItemName(settings), handler.CreatePathItem(context, path));
                }
            }

            if (settings.ShowRootPath)
            {
                OpenApiPathItem rootPath = new()
                {
                    Operations = new Dictionary <OperationType, OpenApiOperation> {
                        {
                            OperationType.Get, new OpenApiOperation {
                                OperationId = "graphService.GetGraphService",
                                Responses   = new OpenApiResponses()
                                {
                                    { "200", new OpenApiResponse()
                                      {
                                          Description = "OK",
                                          Links       = CreateRootLinks(context.EntityContainer)
                                      } }
                                }
                            }
                        }
                    }
                };
                pathItems.Add("/", rootPath);
            }

            return(pathItems);
        }