Swashbuckle Hide unreferenced model

5.3k Views Asked by At

I'm having a problem with Swashbuckle when hiding a call the definition of the model linked to the call remains in the definition in the JSON generated.

Using the Document filter, I'm able to remove the call from the interface.

The calls remain in the JSON generated but are invisible in Swagger UI. We can also see the definition for the Model and Enum linked to theses calls.

Theses are internal calls and need to be hidden from external eyes in the JSON.

How can I hide all the calls and their references?

Using [ApiExplorerSettings(IgnoreApi = true)] would fix my problem but I need to filter with an existing attribute.

2

There are 2 best solutions below

2
On BEST ANSWER

So I found the answer to my question through hard work. I'm putting it here so that the next person with my issue will have a nicer time then me.

public static class SwashbuckleExtensions
{
    public static IEnumerable<Operation> EnumerateOperations(this PathItem pathItem)
    {
        if (pathItem == null)
        {
            yield break;
        }
        yield return pathItem.get;
        yield return pathItem.post;
        yield return pathItem.put;
        yield return pathItem.delete;
        yield return pathItem.options;
        yield return pathItem.head;
    }


    public static IEnumerable<Schema> EnumerateSchema(this Operation operation)
    {
        if (operation == null)
        {
            yield break;
        }
                   foreach (var response in operation.responses ?? new Dictionary<string, Response>())
        {
            yield return response.Value.schema;
            if (response.Value.schema.items != null)
            {
                yield return response.Value.schema.items;
            }
        }
        foreach (var parameter in operation.parameters ?? new List<Parameter>())
        {
            yield return parameter.schema;
        }
    }


    public static IEnumerable<Schema> FindAdditionalSchema(this Schema schema, IDictionary<string, Schema> listOfDefinition)
    {
        if (!string.IsNullOrEmpty(schema.@ref))
        {
            Schema definition;
            if (listOfDefinition.TryGetValue([email protected]("#/definitions/", String.Empty), out definition))
            {
                foreach (var propertySchema in definition.properties)
                {
                    yield return propertySchema.Value;
                }
            }
        }
        if (!string.IsNullOrEmpty( schema?.items?.@ref))
        {
            Schema definition;
            if (listOfDefinition.TryGetValue([email protected]("#/definitions/", String.Empty), out definition))
            {
                foreach (var propertySchema in definition.properties)
                {
                    yield return propertySchema.Value;
                }
            }
        }
    }

    public static IEnumerable<Schema> EnumerateSchema(this Schema schema,IDictionary<string,Schema> listOfDefinition, int dept = 0)
    {
        if (schema == null)
        {
            yield break;
        }
        if (dept > 10)
        {
            yield break;
        }
        if (dept == 0)
        {
            yield return schema;
        }

        var ListOfAdditionalSchema = schema.FindAdditionalSchema(listOfDefinition) ?? new List<Schema>();
        foreach (var additionalSchema in ListOfAdditionalSchema)
        {
            yield return additionalSchema;
            foreach (var childSchema in additionalSchema.EnumerateSchema(listOfDefinition,dept++) ?? new List<Schema>())
            {
                yield return childSchema;
            }
        }
       }
}

Then in the DocumentFilter

    public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
        {


            foreach (var value in swaggerDoc.paths.Values)
            {
                if (value.post != null && value.post.tags.Contains(ToHide))
                    value.post = null;

                if (value.get != null && value.get.tags.Contains(ToHide))
                    value.get = null;

                if (value.put != null && value.put.tags.Contains(ToHide))
                    value.put = null;

                if (value.delete != null && value.delete.tags.Contains(ToHide))
                    value.delete = null;

                if (value.head != null && value.head.tags.Contains(ToHide))
                    value.head = null;

                if (value.options != null && value.options.tags.Contains(ToHide))
                    value.options = null;
            }

            var pathToDelete = swaggerDoc.paths.Where(x => !x.Value.EnumerateOperations().Any(y=>y != null) )
                                               .ToList();//Deleting item from source need list 
            foreach (var item in pathToDelete)
            {
                swaggerDoc.paths.Remove(item.Key);
            }


            var listOfSchemaWithReference = swaggerDoc.paths.SelectMany(x => x.Value.EnumerateOperations())//Find operation by path
                                            .SelectMany(x => x.EnumerateSchema()) //Find schema by operation
                                            .SelectMany(x => x.EnumerateSchema(swaggerDoc.definitions))//Find Schema by schema (dependent schema)
                                            .Where(x=> x?.@ref != null || x?.items?.@ref != null)//I only wany the schema that reference a definition.
                                            .Select(x=> ((x?.@ref) ?? (x.items?.@ref) ).Replace("#/definitions/", String.Empty))//remove the path and keep the Model name
                                            .Distinct()//I dont like duplicates
                                            .ToList();//commit to memory

            //Not finding a definition in the built list of reference means its unreferenced and can be removed.
            var listOfUnreferencedDefinition = swaggerDoc.definitions.Where(x => !listOfSchemaWithReference.Any(y => y == x.Key))
                                                                     .ToList();//Deleting item from source need list 

            foreach (var unreferencedDefinition in listOfUnreferencedDefinition)
            {
                swaggerDoc.definitions.Remove(unreferencedDefinition.Key);
            }
        }
    }
0
On

For JM123's answer above,

.EnumerateSchema(listOfDefinition,dept++) should be a.EnumerateSchema(listOfDefinition,dept+1).

Since this is in a loop, its incrementing depth as it iterates the list, not just as it goes deeper into nesting. With the original code, this starts dropping references for models with a lot of references, even if they are not nested.