private void TryBuildDefaultResponse(string methodName, OperationResponse response, Method method, IModelType headerType)
 {
     IModelType errorModel = null;
     if (SwaggerOperationProducesJson())
     {
         if (TryBuildResponseBody(methodName, response, s => GenerateErrorModelName(s), out errorModel))
         {
             method.DefaultResponse = new Response(errorModel, headerType);
         }
     }
 }
        private bool TryBuildResponseBody(string methodName, OperationResponse response,
            Func<string, string> typeNamer, out IModelType responseType)
        {
            bool handled = false;
            responseType = null;
            if (SwaggerOperationProducesJson())
            {
                if (response.Schema != null)
                {
                    string referenceKey;
                    if (response.Schema.Reference != null)
                    {
                        referenceKey = response.Schema.Reference.StripDefinitionPath();
                        response.Schema.Reference = referenceKey;
                    }
                    else
                    {
                        referenceKey = typeNamer(methodName);
                    }

                    responseType = response.Schema.GetBuilder(_swaggerModeler).BuildServiceType(referenceKey);
                    handled = true;
                }
            }

            return handled;
        }
        private bool TryBuildEmptyResponse(string methodName, HttpStatusCode responseStatusCode,
            OperationResponse response, Method method, List<Stack<IModelType>> types, IModelType headerType)
        {
            bool handled = false;

            if (response.Schema == null)
            {
                method.Responses[responseStatusCode] = new Response(null, headerType);
                handled = true;
            }
            else
            {
                if (_operation.Produces.IsNullOrEmpty())
                {
                    method.Responses[responseStatusCode] = new Response(New<PrimaryType>(KnownPrimaryType.Object), headerType);
                    BuildMethodReturnTypeStack(New<PrimaryType>(KnownPrimaryType.Object), types);
                    handled = true;
                }

                var unwrapedSchemaProperties =
                    _swaggerModeler.Resolver.Unwrap(response.Schema).Properties;
                if (unwrapedSchemaProperties != null && unwrapedSchemaProperties.Any())
                {
                    Logger.LogWarning(Resources.NoProduceOperationWithBody,
                        methodName);
                }
            }

            return handled;
        }
        private bool TryBuildResponse(string methodName, HttpStatusCode responseStatusCode,
            OperationResponse response, Method method, List<Stack<IModelType>> types, IModelType headerType)
        {
            bool handled = false;
            IModelType serviceType;
            if (SwaggerOperationProducesJson())
            {
                if (TryBuildResponseBody(methodName, response,
                    s => GenerateResponseObjectName(s, responseStatusCode), out serviceType))
                {
                    method.Responses[responseStatusCode] = new Response(serviceType, headerType);
                    BuildMethodReturnTypeStack(serviceType, types);
                    handled = true;
                }
            }

            return handled;
        }
        private bool TryBuildStreamResponse(HttpStatusCode responseStatusCode, OperationResponse response,
            Method method, List<Stack<IModelType>> types, IModelType headerType)
        {
            bool handled = false;
            if (SwaggerOperationProducesNotEmpty())
            {
                if (response.Schema != null)
                {
                    IModelType serviceType = response.Schema.GetBuilder(_swaggerModeler)
                        .BuildServiceType(response.Schema.Reference.StripDefinitionPath());

                    Debug.Assert(serviceType != null);

                    BuildMethodReturnTypeStack(serviceType, types);

                    var compositeType = serviceType as CompositeType;
                    if (compositeType != null)
                    {
                        VerifyFirstPropertyIsByteArray(compositeType);
                    }
                    method.Responses[responseStatusCode] = new Response(serviceType, headerType);
                    handled = true;
                }
            }
            return handled;
        }
Beispiel #6
0
        /// <summary>
        /// Compare a modified document node (this) to a previous one and look for breaking as well as non-breaking changes.
        /// </summary>
        /// <param name="context">The modified document context.</param>
        /// <param name="previous">The original document model.</param>
        /// <returns>A list of messages from the comparison.</returns>
        public override IEnumerable <ComparisonMessage> Compare(ComparisonContext context, SwaggerBase previous)
        {
            if (previous == null)
            {
                throw new ArgumentNullException("previous");
            }

            context.CurrentRoot  = this;
            context.PreviousRoot = previous;

            base.Compare(context, previous);

            var previousDefinition = previous as ServiceDefinition;

            if (previousDefinition == null)
            {
                throw new ArgumentException("Comparing a service definition with something else.");
            }

            if (Info != null && previousDefinition.Info != null)
            {
                context.PushProperty("info");
                context.PushProperty("version");

                CompareVersions(context, Info.Version, previousDefinition.Info.Version);

                context.Pop();
                context.Pop();
            }

            if (context.Strict)
            {
                // There was no version change between the documents. This is not an error, but noteworthy.
                context.LogInfo(ComparisonMessages.NoVersionChange);
            }

            // Check that all the protocols of the old version are supported by the new version.

            context.PushProperty("schemes");
            foreach (var scheme in previousDefinition.Schemes)
            {
                if (!Schemes.Contains(scheme))
                {
                    context.LogBreakingChange(ComparisonMessages.ProtocolNoLongerSupported, scheme);
                }
            }
            context.Pop();

            // Check that all the request body formats that were accepted still are.

            context.PushProperty("consumes");
            foreach (var format in previousDefinition.Consumes)
            {
                if (!Consumes.Contains(format))
                {
                    context.LogBreakingChange(ComparisonMessages.RequestBodyFormatNoLongerSupported, format);
                }
            }
            context.Pop();

            // Check that all the response body formats were also supported by the old version.

            context.PushProperty("produces");
            foreach (var format in Produces)
            {
                if (!previousDefinition.Produces.Contains(format))
                {
                    context.LogBreakingChange(ComparisonMessages.ResponseBodyFormatNowSupported, format);
                }
            }
            context.Pop();

            // Check that no paths were removed, and compare the paths that are still there.

            var newPaths = RemovePathVariables(Paths);

            context.PushProperty("paths");
            foreach (var path in previousDefinition.Paths.Keys)
            {
                var p = Regex.Replace(path, @"\{\w*\}", @"{}");

                context.PushProperty(path);

                Dictionary <string, Operation> operations = null;
                if (!newPaths.TryGetValue(p, out operations))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedPath, path);
                }
                else
                {
                    Dictionary <string, Operation> previousOperations = previousDefinition.Paths[path];
                    foreach (var previousOperation in previousOperations)
                    {
                        Operation newOperation = null;
                        if (!operations.TryGetValue(previousOperation.Key, out newOperation))
                        {
                            context.LogBreakingChange(ComparisonMessages.RemovedOperation, previousOperation.Value.OperationId);
                        }
                    }

                    foreach (var operation in operations)
                    {
                        Operation previousOperation = null;
                        if (previousDefinition.Paths[path].TryGetValue(operation.Key, out previousOperation))
                        {
                            context.PushProperty(operation.Key);
                            operation.Value.Compare(context, previousOperation);
                            context.Pop();
                        }
                    }
                }
                context.Pop();
            }
            context.Pop();

            newPaths = RemovePathVariables(CustomPaths);

            context.PushProperty("x-ms-paths");
            foreach (var path in previousDefinition.CustomPaths.Keys)
            {
                var p = Regex.Replace(path, @"\{\w*\}", @"{}");

                context.PushProperty(path);

                Dictionary <string, Operation> operations = null;
                if (!newPaths.TryGetValue(p, out operations))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedPath, path);
                }
                else
                {
                    Dictionary <string, Operation> previousOperations = previousDefinition.CustomPaths[path];
                    foreach (var previousOperation in previousOperations)
                    {
                        Operation newOperation = null;
                        if (!operations.TryGetValue(previousOperation.Key, out newOperation))
                        {
                            context.LogBreakingChange(ComparisonMessages.RemovedOperation, previousOperation.Value.OperationId);
                        }
                    }

                    foreach (var operation in operations)
                    {
                        Operation previousOperation = null;
                        if (previousDefinition.CustomPaths[path].TryGetValue(operation.Key, out previousOperation))
                        {
                            context.PushProperty(operation.Key);
                            operation.Value.Compare(context, previousOperation);
                            context.Pop();
                        }
                    }
                }
                context.Pop();
            }
            context.Pop();

            ReferenceTrackSchemas(this);
            ReferenceTrackSchemas(previousDefinition);

            context.PushProperty("parameters");
            foreach (var def in previousDefinition.Parameters.Keys)
            {
                SwaggerParameter parameter = null;
                if (!Parameters.TryGetValue(def, out parameter))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedClientParameter, def);
                }
                else
                {
                    context.PushProperty(def);
                    parameter.Compare(context, previousDefinition.Parameters[def]);
                    context.Pop();
                }
            }
            context.Pop();

            context.PushProperty("responses");
            foreach (var def in previousDefinition.Responses.Keys)
            {
                OperationResponse response = null;
                if (!Responses.TryGetValue(def, out response))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedDefinition, def);
                }
                else
                {
                    context.PushProperty(def);
                    response.Compare(context, previousDefinition.Responses[def]);
                    context.Pop();
                }
            }
            context.Pop();

            context.PushProperty("definitions");
            foreach (var def in previousDefinition.Definitions.Keys)
            {
                Schema schema    = null;
                Schema oldSchema = previousDefinition.Definitions[def];

                if (!Definitions.TryGetValue(def, out schema))
                {
                    if (oldSchema.IsReferenced)
                    {
                        // It's only an error if the definition is referenced in the old service.
                        context.LogBreakingChange(ComparisonMessages.RemovedDefinition, def);
                    }
                }
                else if (schema.IsReferenced && oldSchema.IsReferenced)
                {
                    context.PushProperty(def);
                    schema.Compare(context, previousDefinition.Definitions[def]);
                    context.Pop();
                }
            }
            context.Pop();

            context.Pop();

            return(context.Messages);
        }
Beispiel #7
0
        /// <summary>
        /// Compare a modified document node (this) to a previous one and look for breaking as well as non-breaking changes.
        /// </summary>
        /// <param name="context">The modified document context.</param>
        /// <param name="previous">The original document model.</param>
        /// <returns>A list of messages from the comparison.</returns>
        public override IEnumerable <ComparisonMessage> Compare(
            ComparisonContext <ServiceDefinition> context,
            ServiceDefinition previousDefinition
            )
        {
            if (context.CurrentRoot != this)
            {
                throw new ArgumentException("context.CurrentRoot != this");
            }
            if (context.PreviousRoot != previousDefinition)
            {
                throw new ArgumentException("context.PreviousRoot != previousDefinition");
            }

            if (previousDefinition == null)
            {
                throw new ArgumentException("Comparing a service definition with something else.");
            }

            base.Compare(context, previousDefinition);

            if (Info?.Version != null &&
                previousDefinition.Info?.Version != null)
            {
                context.PushProperty("info");
                context.PushProperty("version");

                CompareVersions(context, Info.Version, previousDefinition.Info.Version);

                context.Pop();
                context.Pop();
            }

            if (context.Strict)
            {
                // There was no version change between the documents. This is not an error, but noteworthy.
                context.LogInfo(ComparisonMessages.NoVersionChange);
            }

            // Check that all the protocols of the old version are supported by the new version.

            context.PushProperty("schemes");
            foreach (var scheme in previousDefinition.Schemes)
            {
                if (!Schemes.Contains(scheme))
                {
                    context.LogBreakingChange(ComparisonMessages.ProtocolNoLongerSupported, scheme);
                }
            }
            context.Pop();

            // Check that all the request body formats that were accepted still are.

            context.PushProperty("consumes");
            foreach (var format in previousDefinition.Consumes)
            {
                if (!Consumes.Contains(format))
                {
                    context.LogBreakingChange(ComparisonMessages.RequestBodyFormatNoLongerSupported, format);
                }
            }
            context.Pop();

            // Check that all the response body formats were also supported by the old version.

            context.PushProperty("produces");
            foreach (var format in Produces)
            {
                if (!previousDefinition.Produces.Contains(format))
                {
                    context.LogBreakingChange(ComparisonMessages.ResponseBodyFormatNowSupported, format);
                }
            }
            context.Pop();

            // Check that no paths were removed, and compare the paths that are still there.

            var newPaths = RemovePathVariables(Paths);

            context.PushProperty("paths");
            foreach (var path in previousDefinition.Paths.Keys)
            {
                var p = ObjectPath.OpenApiPathName(path);

                context.PushPathProperty(path);

                if (!newPaths.TryGetValue(p, out var operations))
                {
                    if (previousDefinition.Paths[path].Count != 0 && previousDefinition.Paths[path].All(operation => operation.Value.Deprecated))
                    {
                        // Entry path removed contained only deprecated operations, implies path was deprecated
                        context.LogInfo(ComparisonMessages.RemovedDeprecatedpath, path);
                    }
                    else
                    {
                        // Entry path was removeed
                        context.LogBreakingChange(ComparisonMessages.RemovedPath, path);
                    }
                }
                else
                {
                    // 1. Remove this path from the current list to find the added paths
                    newPaths.Remove(p);
                    var copyOfOperations = operations.ToDictionary(e => e.Key, e => e.Value);

                    // 2. look for operation match inside this path
                    var previousOperations = previousDefinition.Paths[path];
                    foreach (var previousOperation in previousOperations)
                    {
                        if (!operations.TryGetValue(previousOperation.Key, out var newOperation))
                        {
                            if (previousOperation.Value.Deprecated)
                            {
                                // Deprecated operation was removed from the path
                                context.LogInfo(ComparisonMessages.RemovedDeprecatedOperation, previousOperation.Value.OperationId);
                            }

                            // Operation was removed from the path
                            context.LogBreakingChange(ComparisonMessages.RemovedOperation, previousOperation.Value.OperationId);
                        }
                        else
                        {
                            copyOfOperations.Remove(previousOperation.Key);
                        }
                    }

                    // Look for added operations
                    foreach (var copyOfOperation in copyOfOperations)
                    {
                        context.PushProperty(copyOfOperation.Key);
                        context.LogInfo(ComparisonMessages.AddedOperation);
                        context.Pop();
                    }

                    // Compare operations
                    foreach (var operation in operations)
                    {
                        if (previousDefinition.Paths[path].TryGetValue(operation.Key, out var previousOperation))
                        {
                            context.PushProperty(operation.Key);
                            operation.Value.Compare(context, previousOperation);
                            context.Pop();
                        }
                    }
                }
                context.Pop();
            }

            // Check wether any new paths are being added
            foreach (var path in newPaths.Keys)
            {
                context.PushPathProperty(path);
                context.LogInfo(ComparisonMessages.AddedPath);
                context.Pop();
            }


            context.Pop();

            // Check for custom paths : x-ms-paths
            var newCustomPaths = RemovePathVariables(CustomPaths);

            context.PushProperty("x-ms-paths");
            foreach (var path in previousDefinition.CustomPaths.Keys)
            {
                var p = ObjectPath.OpenApiPathName(path);

                context.PushPathProperty(path);

                Dictionary <string, Operation> operations = null;
                if (!newCustomPaths.TryGetValue(p, out operations))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedPath, path);
                }
                else
                {
                    // 1. Remove this custom path from the current list to find the added paths
                    newCustomPaths.Remove(p);
                    Dictionary <string, Operation> copyOfOperations = operations.ToDictionary(e => e.Key, e => e.Value);

                    // 2. look for operation match inside this path
                    Dictionary <string, Operation> previousOperations = previousDefinition.CustomPaths[path];
                    foreach (var previousOperation in previousOperations)
                    {
                        Operation newOperation = null;
                        if (!operations.TryGetValue(previousOperation.Key, out newOperation))
                        {
                            context.LogBreakingChange(ComparisonMessages.RemovedOperation, previousOperation.Value.OperationId);
                        }
                    }

                    // Look for added operations
                    foreach (var copyOfOperation in copyOfOperations)
                    {
                        context.PushProperty(copyOfOperation.Key);
                        context.LogInfo(ComparisonMessages.AddedOperation);
                        context.Pop();
                    }

                    // Compare operations
                    foreach (var operation in operations)
                    {
                        Operation previousOperation = null;
                        if (previousDefinition.CustomPaths[path].TryGetValue(operation.Key, out previousOperation))
                        {
                            context.PushProperty(operation.Key);
                            operation.Value.Compare(context, previousOperation);
                            context.Pop();
                        }
                    }
                }
                context.Pop();
            }

            // Check wether any new paths are being added into x-ms-paths
            foreach (var path in newCustomPaths.Keys)
            {
                context.PushPathProperty(path);
                context.LogInfo(ComparisonMessages.AddedPath);
                context.Pop();
            }

            context.Pop();

            ReferenceTrackSchemas(this);
            ReferenceTrackSchemas(previousDefinition);

            context.PushProperty("parameters");
            foreach (var def in previousDefinition.Parameters.Keys)
            {
                SwaggerParameter parameter = null;
                if (!Parameters.TryGetValue(def, out parameter))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedClientParameter, def);
                }
                else
                {
                    context.PushProperty(def);
                    parameter.Compare(context, previousDefinition.Parameters[def]);
                    context.Pop();
                }
            }
            context.Pop();

            context.PushProperty("responses");
            foreach (var def in previousDefinition.Responses.Keys)
            {
                OperationResponse response = null;
                if (!Responses.TryGetValue(def, out response))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedDefinition, def);
                }
                else
                {
                    context.PushProperty(def);
                    response.Compare(context, previousDefinition.Responses[def]);
                    context.Pop();
                }
            }
            context.Pop();

            context.PushProperty("definitions");
            foreach (var def in previousDefinition.Definitions.Keys)
            {
                Schema schema    = null;
                Schema oldSchema = previousDefinition.Definitions[def];

                if (!Definitions.TryGetValue(def, out schema))
                {
                    if (oldSchema.IsReferenced)
                    {
                        // It's only an error if the definition is referenced in the old service.
                        context.LogBreakingChange(ComparisonMessages.RemovedDefinition, def);
                    }
                }
                else
                {
                    context.PushProperty(def);
                    schema.Compare(context, previousDefinition.Definitions[def]);
                    context.Pop();
                }
            }
            context.Pop();

            context.Pop();

            return(context.Messages);
        }