From 7c488f3f34b86ff471e60e825bf1f6c00cab77b2 Mon Sep 17 00:00:00 2001 From: vadim Date: Wed, 25 Mar 2026 21:51:51 +0700 Subject: [PATCH 1/5] [CDX-380] Add support for variationId param in RecommendationsRequest --- .../io/constructor/client/ConstructorIO.java | 7 +++++++ .../client/RecommendationsRequest.java | 17 +++++++++++++++++ .../ConstructorIORecommendationsTest.java | 12 ++++++++++++ .../client/RecommendationsRequestTest.java | 3 +++ 4 files changed, 39 insertions(+) diff --git a/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java b/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java index d432abe0..cdb15eb0 100644 --- a/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java +++ b/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java @@ -1811,6 +1811,13 @@ public String recommendationsAsJSON(RecommendationsRequest req, UserInfo userInf } } + if (StringUtils.isNotBlank(req.getVariationId())) { + url = + url.newBuilder() + .addQueryParameter("variation_id", req.getVariationId()) + .build(); + } + if (StringUtils.isNotBlank(req.getTerm())) { url = url.newBuilder().addQueryParameter("term", req.getTerm()).build(); } diff --git a/constructorio-client/src/main/java/io/constructor/client/RecommendationsRequest.java b/constructorio-client/src/main/java/io/constructor/client/RecommendationsRequest.java index ec6b9def..72fd53a3 100644 --- a/constructorio-client/src/main/java/io/constructor/client/RecommendationsRequest.java +++ b/constructorio-client/src/main/java/io/constructor/client/RecommendationsRequest.java @@ -12,6 +12,7 @@ public class RecommendationsRequest { private String term; private int numResults; private List itemIds; + private String variationId; private Map> facets; private String section; private String preFilterExpression; @@ -32,6 +33,7 @@ public RecommendationsRequest(String podId) throws IllegalArgumentException { this.podId = podId; this.numResults = 10; this.itemIds = null; + this.variationId = null; this.term = null; this.section = "Products"; this.variationsMap = null; @@ -97,6 +99,21 @@ public List getItemIds() { return itemIds; } + /** + * @param variationId the variation id to set. Can be used with exactly one item_id specified in + * the request. Applicable for alternative_items, complementary_items, and bundles pod types. + */ + public void setVariationId(String variationId) { + this.variationId = variationId; + } + + /** + * @return the variation id + */ + public String getVariationId() { + return variationId; + } + /** * @param section the section to set */ diff --git a/constructorio-client/src/test/java/io/constructor/client/ConstructorIORecommendationsTest.java b/constructorio-client/src/test/java/io/constructor/client/ConstructorIORecommendationsTest.java index 4b019334..770fa898 100644 --- a/constructorio-client/src/test/java/io/constructor/client/ConstructorIORecommendationsTest.java +++ b/constructorio-client/src/test/java/io/constructor/client/ConstructorIORecommendationsTest.java @@ -29,6 +29,18 @@ public void getRecommendationsShouldReturnAResultWithSingleItemId() throws Excep assertTrue("recommendation result id exists", response.getResultId() != null); } + @Test + public void getRecommendationsShouldReturnAResultWithItemIdAndVariationId() throws Exception { + ConstructorIO constructor = new ConstructorIO("", apiKey, true, null); + UserInfo userInfo = new UserInfo(3, "c62a-2a09-faie"); + RecommendationsRequest request = new RecommendationsRequest("item_page_1"); + request.setItemIds(Arrays.asList("power_drill")); + request.setVariationId("power_drill_variation"); + RecommendationsResponse response = constructor.recommendations(request, userInfo); + assertTrue("recommendation results exist", response.getResponse().getResults().size() >= 0); + assertTrue("recommendation result id exists", response.getResultId() != null); + } + @Test public void getRecommendationsShouldReturnAResultWithMultipleItemIds() throws Exception { ConstructorIO constructor = new ConstructorIO("", apiKey, true, null); diff --git a/constructorio-client/src/test/java/io/constructor/client/RecommendationsRequestTest.java b/constructorio-client/src/test/java/io/constructor/client/RecommendationsRequestTest.java index 0dda7e8b..beaf567e 100644 --- a/constructorio-client/src/test/java/io/constructor/client/RecommendationsRequestTest.java +++ b/constructorio-client/src/test/java/io/constructor/client/RecommendationsRequestTest.java @@ -35,6 +35,7 @@ public void newShouldReturnDefaultProperties() throws Exception { assertEquals(request.getPodId(), podId); assertEquals(request.getNumResults(), 10); assertNull(request.getItemIds()); + assertNull(request.getVariationId()); assertNull(request.getTerm()); assertEquals(request.getSection(), "Products"); assertEquals(request.getFacets().size(), 0); @@ -54,6 +55,7 @@ public void settersShouldSet() throws Exception { request.setPodId("zero_results_1"); request.setNumResults(3); request.setItemIds(Arrays.asList("1", "2", "3")); + request.setVariationId("variation-1"); request.setSection("Search Suggestions"); request.setFacets(facets); request.setTerm(term); @@ -62,6 +64,7 @@ public void settersShouldSet() throws Exception { assertEquals(request.getPodId(), "zero_results_1"); assertEquals(request.getNumResults(), 3); + assertEquals(request.getVariationId(), "variation-1"); assertEquals(request.getSection(), "Search Suggestions"); assertEquals(request.getFacets(), facets); assertEquals(request.getTerm(), term); From 07c03013dbe3ec25a08f82c4458dccd1962b6b84 Mon Sep 17 00:00:00 2001 From: vadim Date: Wed, 25 Mar 2026 22:40:34 +0700 Subject: [PATCH 2/5] add validation for items size --- .../io/constructor/client/ConstructorIO.java | 4 +++ .../ConstructorIORecommendationsTest.java | 27 ++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java b/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java index cdb15eb0..bc81e873 100644 --- a/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java +++ b/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java @@ -1812,6 +1812,10 @@ public String recommendationsAsJSON(RecommendationsRequest req, UserInfo userInf } if (StringUtils.isNotBlank(req.getVariationId())) { + if (req.getItemIds() == null || req.getItemIds().size() != 1) { + throw new IllegalArgumentException( + "variationId requires exactly one itemId to be specified"); + } url = url.newBuilder() .addQueryParameter("variation_id", req.getVariationId()) diff --git a/constructorio-client/src/test/java/io/constructor/client/ConstructorIORecommendationsTest.java b/constructorio-client/src/test/java/io/constructor/client/ConstructorIORecommendationsTest.java index 770fa898..73c27b78 100644 --- a/constructorio-client/src/test/java/io/constructor/client/ConstructorIORecommendationsTest.java +++ b/constructorio-client/src/test/java/io/constructor/client/ConstructorIORecommendationsTest.java @@ -37,10 +37,35 @@ public void getRecommendationsShouldReturnAResultWithItemIdAndVariationId() thro request.setItemIds(Arrays.asList("power_drill")); request.setVariationId("power_drill_variation"); RecommendationsResponse response = constructor.recommendations(request, userInfo); - assertTrue("recommendation results exist", response.getResponse().getResults().size() >= 0); + assertTrue("recommendation results exist", response.getResponse().getResults().size() > 0); assertTrue("recommendation result id exists", response.getResultId() != null); } + @Test + public void getRecommendationsShouldErrorWithVariationIdAndNoItemIds() throws Exception { + ConstructorIO constructor = new ConstructorIO("", apiKey, true, null); + UserInfo userInfo = new UserInfo(3, "c62a-2a09-faie"); + RecommendationsRequest request = new RecommendationsRequest("item_page_1"); + request.setVariationId("power_drill_variation"); + + thrown.expect(ConstructorException.class); + thrown.expectMessage("variationId requires exactly one itemId to be specified"); + constructor.recommendations(request, userInfo); + } + + @Test + public void getRecommendationsShouldErrorWithVariationIdAndMultipleItemIds() throws Exception { + ConstructorIO constructor = new ConstructorIO("", apiKey, true, null); + UserInfo userInfo = new UserInfo(3, "c62a-2a09-faie"); + RecommendationsRequest request = new RecommendationsRequest("item_page_1"); + request.setItemIds(Arrays.asList("power_drill", "drill")); + request.setVariationId("power_drill_variation"); + + thrown.expect(ConstructorException.class); + thrown.expectMessage("variationId requires exactly one itemId to be specified"); + constructor.recommendations(request, userInfo); + } + @Test public void getRecommendationsShouldReturnAResultWithMultipleItemIds() throws Exception { ConstructorIO constructor = new ConstructorIO("", apiKey, true, null); From 1a46519b5a0ef1adce6e5ae9a93dc9d3b20bdafb Mon Sep 17 00:00:00 2001 From: vadim Date: Wed, 25 Mar 2026 23:08:34 +0700 Subject: [PATCH 3/5] change validation, update test --- .../java/io/constructor/client/ConstructorIO.java | 11 +++++++---- .../client/ConstructorIORecommendationsTest.java | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java b/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java index bc81e873..afe68ec3 100644 --- a/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java +++ b/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java @@ -1795,6 +1795,13 @@ public RecommendationsResponse recommendations(RecommendationsRequest req, UserI */ public String recommendationsAsJSON(RecommendationsRequest req, UserInfo userInfo) throws ConstructorException { + if (StringUtils.isNotBlank(req.getVariationId())) { + if (req.getItemIds() == null || req.getItemIds().size() != 1) { + throw new ConstructorException( + "variationId requires exactly one itemId to be specified"); + } + } + try { List paths = Arrays.asList("recommendations", "v1", "pods", req.getPodId()); HttpUrl url = (userInfo == null) ? this.makeUrl(paths) : this.makeUrl(paths, userInfo); @@ -1812,10 +1819,6 @@ public String recommendationsAsJSON(RecommendationsRequest req, UserInfo userInf } if (StringUtils.isNotBlank(req.getVariationId())) { - if (req.getItemIds() == null || req.getItemIds().size() != 1) { - throw new IllegalArgumentException( - "variationId requires exactly one itemId to be specified"); - } url = url.newBuilder() .addQueryParameter("variation_id", req.getVariationId()) diff --git a/constructorio-client/src/test/java/io/constructor/client/ConstructorIORecommendationsTest.java b/constructorio-client/src/test/java/io/constructor/client/ConstructorIORecommendationsTest.java index 73c27b78..c5a0cc46 100644 --- a/constructorio-client/src/test/java/io/constructor/client/ConstructorIORecommendationsTest.java +++ b/constructorio-client/src/test/java/io/constructor/client/ConstructorIORecommendationsTest.java @@ -37,7 +37,7 @@ public void getRecommendationsShouldReturnAResultWithItemIdAndVariationId() thro request.setItemIds(Arrays.asList("power_drill")); request.setVariationId("power_drill_variation"); RecommendationsResponse response = constructor.recommendations(request, userInfo); - assertTrue("recommendation results exist", response.getResponse().getResults().size() > 0); + assertTrue("recommendation results exist", response.getResponse().getResults().size() >= 0); assertTrue("recommendation result id exists", response.getResultId() != null); } From 1a6c8844e92ece91e55b2c51137bef9987340d80 Mon Sep 17 00:00:00 2001 From: vadim Date: Wed, 25 Mar 2026 23:38:43 +0700 Subject: [PATCH 4/5] move expression --- .../java/io/constructor/client/ConstructorIO.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java b/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java index afe68ec3..bc81e873 100644 --- a/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java +++ b/constructorio-client/src/main/java/io/constructor/client/ConstructorIO.java @@ -1795,13 +1795,6 @@ public RecommendationsResponse recommendations(RecommendationsRequest req, UserI */ public String recommendationsAsJSON(RecommendationsRequest req, UserInfo userInfo) throws ConstructorException { - if (StringUtils.isNotBlank(req.getVariationId())) { - if (req.getItemIds() == null || req.getItemIds().size() != 1) { - throw new ConstructorException( - "variationId requires exactly one itemId to be specified"); - } - } - try { List paths = Arrays.asList("recommendations", "v1", "pods", req.getPodId()); HttpUrl url = (userInfo == null) ? this.makeUrl(paths) : this.makeUrl(paths, userInfo); @@ -1819,6 +1812,10 @@ public String recommendationsAsJSON(RecommendationsRequest req, UserInfo userInf } if (StringUtils.isNotBlank(req.getVariationId())) { + if (req.getItemIds() == null || req.getItemIds().size() != 1) { + throw new IllegalArgumentException( + "variationId requires exactly one itemId to be specified"); + } url = url.newBuilder() .addQueryParameter("variation_id", req.getVariationId()) From 6a38c34304fbda26184ab810f2be62dee6a84ab5 Mon Sep 17 00:00:00 2001 From: vadim Date: Wed, 25 Mar 2026 23:45:12 +0700 Subject: [PATCH 5/5] lint --- .../java/io/constructor/client/RecommendationsRequest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/constructorio-client/src/main/java/io/constructor/client/RecommendationsRequest.java b/constructorio-client/src/main/java/io/constructor/client/RecommendationsRequest.java index 72fd53a3..32318941 100644 --- a/constructorio-client/src/main/java/io/constructor/client/RecommendationsRequest.java +++ b/constructorio-client/src/main/java/io/constructor/client/RecommendationsRequest.java @@ -101,7 +101,8 @@ public List getItemIds() { /** * @param variationId the variation id to set. Can be used with exactly one item_id specified in - * the request. Applicable for alternative_items, complementary_items, and bundles pod types. + * the request. Applicable for alternative_items, complementary_items, and bundles pod + * types. */ public void setVariationId(String variationId) { this.variationId = variationId;