question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Feature Request] Overriding individual Property & Parameter types with [JsonSchema] Attribute

See original GitHub issue

In some cases specific properties need to have their Schema type overriden. I would have thought that SwaggerGen would accept the use of the [JsonSchema] attribute from NJsonSchema, but it doesn’t seem to affect the generated schema.

Example 1:

    public class TagResponse
    {
        [JsonSchema(JsonObjectType.String)]
        [JsonConverter(typeof(HashIdsConverter))]
        public int? Id { get; set; }
        public string Name { get; set; }
    }

Here the int Id is converted to and from a string in the form of a HashId (ie. Id 5 == gR8q5b). I have specified that the JsonSchema of the type, yet it still comes out as an int in the Swagger models.

Example 2:

        [HttpGet(TagRoutes.Get, Name = "GetTag")]
        [HashIdFilter(TagRoutes.IdParam)]
        public ActionResult<TagResponse> Get([JsonSchema(JsonObjectType.String)] int tagId)
        {
              //Do stuff
        }

Here the id parameter is an int and I have this action annotated with a filter. This filter transparently converts the int id to and from the string HashId. Requests are expected to provide a string Id, and responses respond with a string Id. However, the Swagger UI shows this as requiring an int which removes the ability to test this endpoint through Swagger as strings are not accepted to execute a request…


Can this library support the use of the [JsonSchema] attribute to override the schema types of individual properties and parameters?

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
domaindrivendevcommented, Sep 12, 2019

Sorry, I misinterpreted your original post.

Swashbuckle does have an “add-on” package (described here) for overriding the generated Swagger with attributes. That package doesn’t currently support your use case but could be updated to do so relatively easily if you’re interested in contributing?

With that said, an attribute-based approach puts the burden of aligning documentation with actual behavior on the API developer, and this deviates somewhat from the projects original goals. Instead I would encourage the use of “Swagger filters” (described here) to hook into the Swagger generation process and automatically honor the custom serialization behaviors you’ve implemented in HashIdsConverter and HashIdFilter.

For example, you could wire up the following Schema Filter to automatically detect properties decorated with your custom converter and override the schema accordingly.

// HashIdsSchemaFilter.cs
public class HashIdsSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        var jsonObjectContract = context.JsonContract as JsonObjectContract;
        if (jsonObjectContract == null) return;

        foreach (var propertyName in schema.Properties.Keys)
        {
            var propertySchema = schema.Properties[propertyName];

            // Get the underying PropertyInfo
            var jsonProperty = jsonObjectContract.Properties[propertyName];
            var propertyInfo = jsonProperty.DeclaringType.GetProperty(jsonProperty.UnderlyingName);

            // Check if it's decorated with the specific converter
            var jsonConverterAttribute = propertyInfo.GetCustomAttributes(true)
                .OfType<JsonConverterAttribute>()
                .FirstOrDefault();

            if (jsonConverterAttribute != null && jsonConverterAttribute.ConverterType == typeof(HashIdsConverter))
            {
                propertySchema.Type = "string";
                propertySchema.Format = null;
            }
        }
    }
}

// Startup.cs
c.AddSwaggerGen(c =>
{
    ...
    c.SchemaFilter<HashIdsSchemaFilter>();
});

For the second scenario (i.e. where you’ve customized the parameter serialization behavior with HashIdFilter), you would do something similar but with an Operation Filter instead.

0reactions
wizofauscommented, Mar 3, 2021

BTW, I figured it out how to add that functionality by picking up the ‘cref’ parameter from xml comments, just need to add this to the end of XmlCommentsParameterFilter.ApplyParamTags:

                var cref = paramNode.GetAttribute("cref", "")?.Split(':').Last();
                if (!string.IsNullOrEmpty(cref) && System.Type.GetType(cref) is System.Type type)
                {
                    parameter.Schema = context.SchemaGenerator.GenerateSchema(type, context.SchemaRepository);
                }

Obviously could use some error handling etc., but the basic principle works. I’m not quite sure why the xml file has “T:” pre-pended to whatever type name you put in the cref attribute currently, hence the Split(':').Last().

Read more comments on GitHub >

github_iconTop Results From Across the Web

How do I override example for specific properties in ...
... application/json: schema: $ref: "#/components/schemas/Pet" example: customName: IvanovOverride components: ...
Read more >
Redefine Required Property of referenced JSON Schema
"lineitem": { "name": "Item", "description": "Single item found in an order.", "type": "object", "additionalProperties": true, "allOf":[{ "ref": ...
Read more >
Structuring a complex schema
When an object contains a $ref property, the object is considered a reference, not a schema. Therefore, any other properties you put in...
Read more >
JSON Schema Serializer and Deserializer
properties Indicates whether JSON schemas derived from objects will fail if unknown properties are encountered. The default boolean value is true . json.write....
Read more >
OpenAPI Specification - Version 3.0.3
As defined by the JSON Schema Validation vocabulary, data types can have an optional modifier property: format . OAS defines additional formats to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found