From bd516473fbeeb47ca05eaf510734f06432c4280a Mon Sep 17 00:00:00 2001 From: Aaron Klish Date: Wed, 3 Jun 2020 09:09:44 -0500 Subject: [PATCH] Disabling Legacy Filter Dialect in Swagger Documentation (#1363) * Disabling Legacy Filter Dialect in Swagger Documentation * Fixed test ordering issue * Inspection rework Co-authored-by: Aaron Klish --- .../elide/contrib/swagger/SwaggerBuilder.java | 76 ++++++++++++------ .../contrib/swagger/SwaggerBuilderTest.java | 77 +++++++++++++++++++ .../swagger/SwaggerResourceConfig.java | 2 +- .../elide/example/CommonElideSettings.java | 2 +- .../spring/config/ElideAutoConfiguration.java | 2 +- .../elide/standalone/ElideStandaloneTest.java | 2 +- 6 files changed, 134 insertions(+), 27 deletions(-) diff --git a/elide-contrib/elide-swagger/src/main/java/com/yahoo/elide/contrib/swagger/SwaggerBuilder.java b/elide-contrib/elide-swagger/src/main/java/com/yahoo/elide/contrib/swagger/SwaggerBuilder.java index ca8f1798ed..b947d60f1b 100644 --- a/elide-contrib/elide-swagger/src/main/java/com/yahoo/elide/contrib/swagger/SwaggerBuilder.java +++ b/elide-contrib/elide-swagger/src/main/java/com/yahoo/elide/contrib/swagger/SwaggerBuilder.java @@ -56,6 +56,8 @@ public class SwaggerBuilder { protected Map globalResponses; protected Set globalParams; protected Set filterOperators; + protected boolean supportLegacyDialect; + protected boolean supportRSQLDialect; public static final Response UNAUTHORIZED_RESPONSE = new Response().description("Unauthorized"); public static final Response FORBIDDEN_RESPONSE = new Response().description("Forbidden"); @@ -495,33 +497,39 @@ private List getFilterParameters() { List params = new ArrayList<>(); - /* Add RSQL Disjoint Filter Query Param */ - params.add(new QueryParameter() - .type("string") - .name("filter[" + typeName + "]") - .description("Filters the collection of " + typeName + " using a 'disjoint' RSQL expression")); - - if (lineage.isEmpty()) { - /* Add RSQL Joined Filter Query Param */ + if (supportRSQLDialect) { + /* Add RSQL Disjoint Filter Query Param */ params.add(new QueryParameter() .type("string") - .name("filter") - .description("Filters the collection of " + typeName + " using a 'joined' RSQL expression")); + .name("filter[" + typeName + "]") + .description("Filters the collection of " + typeName + + " using a 'disjoint' RSQL expression")); + + if (lineage.isEmpty()) { + /* Add RSQL Joined Filter Query Param */ + params.add(new QueryParameter() + .type("string") + .name("filter") + .description("Filters the collection of " + typeName + + " using a 'joined' RSQL expression")); + } } - for (Operator op : filterOperators) { - attributeNames.forEach((name) -> { - Class attributeClass = dictionary.getType(type, name); - - /* Only filter attributes that can be assigned to strings or primitives */ - if (attributeClass.isPrimitive() || String.class.isAssignableFrom(attributeClass)) { - params.add(new QueryParameter() - .type("string") - .name("filter[" + typeName + "." + name + "][" + op.getNotation() + "]") - .description("Filters the collection of " + typeName + " by the attribute " - + name + " " + "using the operator " + op.getNotation())); - } - }); + if (supportLegacyDialect) { + for (Operator op : filterOperators) { + attributeNames.forEach((name) -> { + Class attributeClass = dictionary.getType(type, name); + + /* Only filter attributes that can be assigned to strings or primitives */ + if (attributeClass.isPrimitive() || String.class.isAssignableFrom(attributeClass)) { + params.add(new QueryParameter() + .type("string") + .name("filter[" + typeName + "." + name + "][" + op.getNotation() + "]") + .description("Filters the collection of " + typeName + " by the attribute " + + name + " " + "using the operator " + op.getNotation())); + } + }); + } } return params; @@ -605,6 +613,8 @@ private boolean lineageContainsType(PathMetaData other) { */ public SwaggerBuilder(EntityDictionary dictionary, Info info) { this.dictionary = dictionary; + this.supportLegacyDialect = true; + this.supportRSQLDialect = true; globalResponses = new HashMap<>(); globalParams = new HashSet<>(); allClasses = new HashSet<>(); @@ -636,6 +646,26 @@ public SwaggerBuilder withGlobalResponse(int code, Response response) { return this; } + /** + * Turns on or off the legacy filter dialect. + * @param enableLegacyDialect Whether or not to enable the legacy filter dialect. + * @return the builder + */ + public SwaggerBuilder withLegacyFilterDialect(boolean enableLegacyDialect) { + supportLegacyDialect = enableLegacyDialect; + return this; + } + + /** + * Turns on or off the RSQL filter dialect. + * @param enableRSQLDialect Whether or not to enable the RSQL filter dialect. + * @return the builder + */ + public SwaggerBuilder withRSQLFilterDialect(boolean enableRSQLDialect) { + supportRSQLDialect = enableRSQLDialect; + return this; + } + /** * Decorates every path with the given parameter. * @param param the parameter to decorate diff --git a/elide-contrib/elide-swagger/src/test/java/com/yahoo/elide/contrib/swagger/SwaggerBuilderTest.java b/elide-contrib/elide-swagger/src/test/java/com/yahoo/elide/contrib/swagger/SwaggerBuilderTest.java index 40ade616fa..c919a14e98 100644 --- a/elide-contrib/elide-swagger/src/test/java/com/yahoo/elide/contrib/swagger/SwaggerBuilderTest.java +++ b/elide-contrib/elide-swagger/src/test/java/com/yahoo/elide/contrib/swagger/SwaggerBuilderTest.java @@ -600,6 +600,83 @@ class NothingToSort { assertEquals(sortValues, ((StringProperty) sortParam.getItems()).getEnum()); } + @Test + public void testAllFilterParameters() throws Exception { + Info info = new Info() + .title("Test Service"); + + SwaggerBuilder builder = new SwaggerBuilder(dictionary, info); + Swagger swagger = builder.build(); + + Operation op = swagger.getPaths().get("/book").getGet(); + + List paramNames = op.getParameters().stream() + .filter(param -> param.getName().startsWith("filter")) + .map(Parameter::getName) + .sorted() + .collect(Collectors.toList()); + + List expectedNames = Arrays.asList("filter", "filter[book.title][ge]", "filter[book.title][gt]", + "filter[book.title][in]", "filter[book.title][infix]", "filter[book.title][isnull]", + "filter[book.title][le]", "filter[book.title][lt]", "filter[book.title][not]", + "filter[book.title][notnull]", "filter[book.title][postfix]", "filter[book.title][prefix]", + "filter[book.year][ge]", "filter[book.year][gt]", "filter[book.year][in]", "filter[book.year][infix]", + "filter[book.year][isnull]", "filter[book.year][le]", "filter[book.year][lt]", "filter[book.year][not]", + "filter[book.year][notnull]", "filter[book.year][postfix]", "filter[book.year][prefix]", + "filter[book]"); + + assertEquals(expectedNames, paramNames); + } + + @Test + public void testRsqlOnlyFilterParameters() throws Exception { + Info info = new Info() + .title("Test Service"); + + SwaggerBuilder builder = new SwaggerBuilder(dictionary, info); + builder = builder.withLegacyFilterDialect(false); + Swagger swagger = builder.build(); + + Operation op = swagger.getPaths().get("/book").getGet(); + + List paramNames = op.getParameters().stream() + .filter(param -> param.getName().startsWith("filter")) + .map(Parameter::getName) + .sorted() + .collect(Collectors.toList()); + + List expectedNames = Arrays.asList("filter", "filter[book]"); + + assertEquals(expectedNames, paramNames); + } + + @Test + public void testLegacyOnlyFilterParameters() throws Exception { + Info info = new Info() + .title("Test Service"); + + SwaggerBuilder builder = new SwaggerBuilder(dictionary, info); + builder = builder.withRSQLFilterDialect(false); + Swagger swagger = builder.build(); + + Operation op = swagger.getPaths().get("/book").getGet(); + + List paramNames = op.getParameters().stream() + .filter(param -> param.getName().startsWith("filter")) + .map(Parameter::getName) + .sorted() + .collect(Collectors.toList()); + + List expectedNames = Arrays.asList("filter[book.title][ge]", "filter[book.title][gt]", + "filter[book.title][in]", "filter[book.title][infix]", "filter[book.title][isnull]", + "filter[book.title][le]", "filter[book.title][lt]", "filter[book.title][not]", + "filter[book.title][notnull]", "filter[book.title][postfix]", "filter[book.title][prefix]", + "filter[book.year][ge]", "filter[book.year][gt]", "filter[book.year][in]", "filter[book.year][infix]", + "filter[book.year][isnull]", "filter[book.year][le]", "filter[book.year][lt]", "filter[book.year][not]", + "filter[book.year][notnull]", "filter[book.year][postfix]", "filter[book.year][prefix]"); + + assertEquals(expectedNames, paramNames); + } /** * Verifies that the given property is of type 'Data' containing a reference to the given model. diff --git a/elide-contrib/elide-swagger/src/test/java/com/yahoo/elide/contrib/swagger/SwaggerResourceConfig.java b/elide-contrib/elide-swagger/src/test/java/com/yahoo/elide/contrib/swagger/SwaggerResourceConfig.java index 52220ae32d..1935330730 100644 --- a/elide-contrib/elide-swagger/src/test/java/com/yahoo/elide/contrib/swagger/SwaggerResourceConfig.java +++ b/elide-contrib/elide-swagger/src/test/java/com/yahoo/elide/contrib/swagger/SwaggerResourceConfig.java @@ -40,7 +40,7 @@ public Map provide() { dictionary.bindEntity(Publisher.class); Info info = new Info().title("Test Service").version("1.0"); - SwaggerBuilder builder = new SwaggerBuilder(dictionary, info); + SwaggerBuilder builder = new SwaggerBuilder(dictionary, info).withLegacyFilterDialect(false); Swagger swagger = builder.build(); Map docs = new HashMap<>(); diff --git a/elide-example/elide-blog-example/src/main/java/com/yahoo/elide/example/CommonElideSettings.java b/elide-example/elide-blog-example/src/main/java/com/yahoo/elide/example/CommonElideSettings.java index d3e2f1c7fb..943bf37946 100644 --- a/elide-example/elide-blog-example/src/main/java/com/yahoo/elide/example/CommonElideSettings.java +++ b/elide-example/elide-blog-example/src/main/java/com/yahoo/elide/example/CommonElideSettings.java @@ -41,7 +41,7 @@ public Map enableSwagger() { dictionary.bindEntity(Comment.class); Info info = new Info().title("Test Service").version("1.0"); - SwaggerBuilder builder = new SwaggerBuilder(dictionary, info); + SwaggerBuilder builder = new SwaggerBuilder(dictionary, info).withLegacyFilterDialect(false); Swagger swagger = builder.build(); Map docs = new HashMap<>(); diff --git a/elide-spring/elide-spring-boot-autoconfigure/src/main/java/com/yahoo/elide/spring/config/ElideAutoConfiguration.java b/elide-spring/elide-spring-boot-autoconfigure/src/main/java/com/yahoo/elide/spring/config/ElideAutoConfiguration.java index 55d9b38fbb..ccd2fa78ec 100644 --- a/elide-spring/elide-spring-boot-autoconfigure/src/main/java/com/yahoo/elide/spring/config/ElideAutoConfiguration.java +++ b/elide-spring/elide-spring-boot-autoconfigure/src/main/java/com/yahoo/elide/spring/config/ElideAutoConfiguration.java @@ -116,7 +116,7 @@ public Swagger buildSwagger(EntityDictionary dictionary, ElideConfigProperties s .title(settings.getSwagger().getName()) .version(settings.getSwagger().getVersion()); - SwaggerBuilder builder = new SwaggerBuilder(dictionary, info); + SwaggerBuilder builder = new SwaggerBuilder(dictionary, info).withLegacyFilterDialect(false); Swagger swagger = builder.build().basePath(settings.getJsonApi().getPath()); diff --git a/elide-standalone/src/test/java/com/yahoo/elide/standalone/ElideStandaloneTest.java b/elide-standalone/src/test/java/com/yahoo/elide/standalone/ElideStandaloneTest.java index fb731a3441..4f243c2549 100644 --- a/elide-standalone/src/test/java/com/yahoo/elide/standalone/ElideStandaloneTest.java +++ b/elide-standalone/src/test/java/com/yahoo/elide/standalone/ElideStandaloneTest.java @@ -75,7 +75,7 @@ public Map enableSwagger() { dictionary.bindEntity(Post.class); Info info = new Info().title("Test Service").version("1.0"); - SwaggerBuilder builder = new SwaggerBuilder(dictionary, info); + SwaggerBuilder builder = new SwaggerBuilder(dictionary, info).withLegacyFilterDialect(false); Swagger swagger = builder.build(); Map docs = new HashMap<>();