Swagger-core: Add support for @JsonView

Created on 5 Mar 2014  路  29Comments  路  Source: swagger-api/swagger-core

In java, many REST services are written using Jersey/dropwizard frameworks and which rely on the Jackson Json library for serialization. With this Jackson library they allow us to define a "JsonView" which acts as a subset of a model that might be exposed via an api (http://wiki.fasterxml.com/JacksonJsonViews).

For example if I have a resource annotated with the following...

@JsonView(View.Public.class)
@ApiOperation(value = "bla bla bal.", notes = "And bla bla bla.",
        response = SomeType.class)
Response getSomeResource() {}

Where the class SomeType looks like this:

class SomeType {
  @JsonView(View.Public.class)
   private String publicProperty;
  @JsonView(View.Internal.class)
   private String internalProperty;
}

I want the swagger docs to only include the property "publicProperty" since it was annotated with the @JsonView(View.Public.class). This dropwizard/jersey resource renders the correct response, but swagger still generates api docs that include both properties.

Is it possible to fix this or is there a swagger change coming that might fix this? I've heard that in the most recent SNAPSHOT of swagger that there's support for "@ApiModelProperty(hidden=true)", but I'd rather not have to duplicate annotating my models like this especially since I think the @JsonView is more flexible.

Thanks,
Brent

Feature P3

Most helpful comment

Hm it is still not resolved in my opinion. This api implicit model only supports manual setted parameters... that means we have to write it :

in jsonviews + in swagger doc

If jsonviews was supported we only had to write into jsonviews.
Please support it

All 29 comments

+1

Is there any consideration of this? Or any sort of workaround to make it at all possible? We have multiple views per class and would like to be able to customize the view by endpoint (i.e., we can't hide properties across the board because some properties are shown in some services and not in others).

+1

+1

+1

1.5.0 will use pure jackson and therefore the @JsonView annotation.

I'd love to see some samples committed to the develop_2.0 branch to cover @JsonView use cases.

I know this has gone unanswered for a long time, and I hate to do this, but that functionality just doesn't fit in with swagger. I suggest using filters to attain a similar result, which gives you even more control since the determination is dynamic.

https://github.com/swagger-api/swagger-core/blob/develop_2.0/modules/swagger-core/src/main/java/com/wordnik/swagger/core/filter/SwaggerSpecFilter.java

fyi, the filters do not solve the problem here and suck to implement.

fehguy, your link gives 404

+1

+1

Hm it is still not resolved in my opinion. This api implicit model only supports manual setted parameters... that means we have to write it :

in jsonviews + in swagger doc

If jsonviews was supported we only had to write into jsonviews.
Please support it

+1

+1

+1

+1

+1

+1

+1

@fehguy Thanks for your comment. I don't think SwaggerSpecFilter can be of any help as the limitation resides in the OAI syntax itself.

Taking this example (pseudo code):

@GET(/serviceA)
@JsonView(ViewA.class)
public MyModel methodA() {...}

@GET(/serviceB)
@JsonView(ViewB.class)
public MyModel methodB() {...}

=> parsing these two resources will translate into the following OAI JSON file:

paths: {
   /serviceA:
     get ->  responses: { 200-> $ref: #/definitions/MyModel }
   /serviceB: {
     get ->  responses: { 200-> $ref: #/definitions/MyModel }
},
definitions: {
  MyModel:
      type: object,
      required: [
        propertyForServiceA,
        propertyNotForServiceB
      ]
}

Sadly, method SwaggerSpecFilter#isPropertyAllowed() is invoked only once, either after scanning serviceA or serviceB.

Would it be difficult to instead generate a 'contextualized' definition model which could have then different properties (hidden or not), like:

definitions: {
  MyModel-serviceA.get:
      type: object,
      required: [
        propertyForServiceA,
        propertyNotForServiceB
      ]
  MyModel-serviceB.get:
      type: object,
      required: [
        propertyForServiceB
      ]
}

+1

I also just ran into this! Another idea might be to change the property definition to allow for a views field that holds the views to which the property applies?

Another alternative to using JSON views that will get you a more precise swagger definition is to leverage Java 8's "mixin" capability with default interface methods. For example one can define a base Representation class and PropertyBag interface as such:

public interface PropertyBag {

    <T> T get(String key);

    <T> void set(String key, T value);
}

public class Representation implements PropertyBag {

    private Map<String, Object> properties;

    public Representation() {
        this.properties = new HashMap();
    }

    public <T> T get(String key) {
        return (T) this.properties.get(key);
    }

    public <T> void set(String key, T value) {
        this.properties.put(key, value);
    }
}

public interface Creatable extends PropertyBag {

    @ApiModelProperty(
        value = "The time in UTC when the resource was created in the ISO 8601 format "
        + "yyyy-MM-dd'T'HH:mm:ssZ.",
        required = true
        )
    default DateTime getCreatedAt() {
        return this.<DateTime>get("createdAt");
    }

    default void setCreatedAt(DateTime createdAt) {
        this.<DateTime>set("createdAt", createdAt);
    }
}

You can then make "mixins" of common properties...

public interface DisplayOrderable extends PropertyBag {

    @ApiModelProperty(
        value = "The display order of this entity.",
        required = true)
    default Integer getDisplayOrder() {
        return this.<Integer>get("displayOrder");
    }

    default void setDisplayOrder(Integer displayOrder) {
        this.<Integer>set("displayOrder", displayOrder);
    }
}

... and subclasses of the base Representation class as such:

@ApiModel(...)
public class MyEntityRead extends Representation implements Creatable, DisplayOrderable {}

@ApiModel(...)
public class MyEntityCreate extends Representation implements DisplayOrderable {}

Full @JsonView support would be ideal, but this approach lets you define precise models for different situations whilst cutting down on code duplication.

+1

+1

Yeah, this feature would be much appreciated.

+1

Strictly speaking, the appropriate JsonView is dynamically specified. For our purposes, we don't need that generality.

What would work just fine for us is to have a new @ApiJsonView annotation that contains the JsonView class and to have the Swagger object-graph walker just do the same test against that that Jackson does.

That change doesn't sound very hard.

Was this page helpful?
0 / 5 - 0 ratings