Skip to content

Commit fdbd861

Browse files
committed
feat: add method RequestBuilder.resolveRequestUrl
1 parent 4d94158 commit fdbd861

File tree

3 files changed

+209
-14
lines changed

3 files changed

+209
-14
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<compiler-plugin-version>3.8.0</compiler-plugin-version>
4343
<okhttp3-version>3.14.9</okhttp3-version>
4444
<logback-version>1.2.3</logback-version>
45-
<guava-version>27.1-android</guava-version>
45+
<guava-version>29.0-jre</guava-version>
4646
<gson-version>2.8.5</gson-version>
4747
<commons-codec-version>1.12</commons-codec-version>
4848
<commons-io-version>2.6</commons-io-version>

src/main/java/com/ibm/cloud/sdk/core/http/RequestBuilder.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@
1616
import java.io.InputStream;
1717
import java.util.ArrayList;
1818
import java.util.List;
19+
import java.util.Map;
20+
import java.util.Map.Entry;
1921

22+
import org.apache.commons.lang3.StringUtils;
23+
24+
import com.google.common.escape.Escaper;
25+
import com.google.common.net.UrlEscapers;
2026
import com.google.gson.Gson;
2127
import com.google.gson.JsonObject;
2228
import com.ibm.cloud.sdk.core.util.GsonSingleton;
@@ -34,6 +40,8 @@
3440
*/
3541
public class RequestBuilder {
3642

43+
private static Escaper pathEscaper = UrlEscapers.urlPathSegmentEscaper();
44+
3745
private enum HTTPMethod {
3846
DELETE, GET, POST, PUT, PATCH, HEAD
3947
}
@@ -145,6 +153,64 @@ public static HttpUrl constructHttpUrl(String serviceUrl, String[] pathSegments,
145153
return httpUrlBuilder.build();
146154
}
147155

156+
/**
157+
* Resolves a request URL by first resolving path parameter references within "path",
158+
* then it combines the serviceUrl portion with the resolved path string.
159+
* @param serviceUrl the base URL associated with a service instance
160+
* @param path the unresolved path
161+
* @param pathParams a map containing path parameters, keyed by the parameter name
162+
* @return an HttpUrl instance that holds the request URL
163+
*/
164+
public static HttpUrl resolveRequestUrl(String serviceUrl, String path, Map<String, String> pathParams) {
165+
Validator.notEmpty(serviceUrl, "The serviceUrl cannot be null");
166+
167+
// Create a builder based on the service's base URL.
168+
// Note: in case of an error, the "get" method will throw an exception.
169+
HttpUrl.Builder builder = HttpUrl.get(serviceUrl).newBuilder();
170+
171+
if (StringUtils.isNotEmpty(path)) {
172+
173+
// If path parameter values were passed in, then for each one, replace any references to it
174+
// within "path" with the path parameter's encoded value.
175+
if (pathParams != null) {
176+
for (Entry<String, String> paramEntry : pathParams.entrySet()) {
177+
if (StringUtils.isEmpty(paramEntry.getValue())) {
178+
throw new IllegalArgumentException(
179+
String.format("Path parameter '%s' is empty", paramEntry.getKey()));
180+
}
181+
182+
// Encode the individual path param value as a path segment, then replace its reference(s)
183+
// within the path string with the encoded value.
184+
String encodedValue = pathEscaper.escape(paramEntry.getValue());
185+
String ref = String.format("{%s}", paramEntry.getKey());
186+
path = path.replace(ref, encodedValue);
187+
}
188+
}
189+
190+
// Strip off any leading slash from the path string.
191+
if (path.startsWith("/")) {
192+
path = path.substring(1);
193+
}
194+
195+
// Set the path on the builder object.
196+
builder.addEncodedPathSegments(path);
197+
}
198+
199+
// Return the final HttpUrl object.
200+
return builder.build();
201+
}
202+
203+
/**
204+
* Similar to the three-arg version of resolveRequestUrl, but supports
205+
* a "path" parameter with no path param references.
206+
* @param serviceUrl the base URL associated with a service instance
207+
* @param path the path string
208+
* @return an HttpUrl instance that holds the request URL
209+
*/
210+
public static HttpUrl resolveRequestUrl(String serviceUrl, String path) {
211+
return resolveRequestUrl(serviceUrl, path, null);
212+
}
213+
148214
private RequestBody body;
149215
private HttpUrl httpUrl;
150216
private final List<NameValue> formParams = new ArrayList<NameValue>();

src/test/java/com/ibm/cloud/sdk/core/test/service/RequestBuilderTest.java

Lines changed: 142 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,20 @@
1313

1414
package com.ibm.cloud.sdk.core.test.service;
1515

16+
import static org.junit.Assert.assertEquals;
17+
import static org.junit.Assert.assertNotNull;
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
import java.io.InputStream;
22+
import java.util.ArrayList;
23+
import java.util.Arrays;
24+
import java.util.HashMap;
25+
import java.util.List;
26+
import java.util.Map;
27+
28+
import org.junit.Test;
29+
1630
import com.google.gson.JsonObject;
1731
import com.ibm.cloud.sdk.core.http.HttpMediaType;
1832
import com.ibm.cloud.sdk.core.http.RequestBuilder;
@@ -27,22 +41,11 @@
2741
import okhttp3.Request;
2842
import okhttp3.RequestBody;
2943
import okio.Buffer;
30-
import org.junit.Test;
31-
32-
import java.io.File;
33-
import java.io.IOException;
34-
import java.io.InputStream;
35-
import java.util.Arrays;
36-
import java.util.ArrayList;
37-
import java.util.List;
38-
39-
import static org.junit.Assert.assertEquals;
40-
import static org.junit.Assert.assertNotNull;
41-
import static org.junit.Assert.assertNotEquals;
4244

4345
/**
4446
* The Class RequestBuilderTest.
4547
*/
48+
@SuppressWarnings("serial")
4649
public class RequestBuilderTest {
4750

4851
private static final String X_TOKEN = "x-token";
@@ -283,7 +286,7 @@ public void testConstructHttpUrlGood() {
283286
String[] pathParameters = { "param1", "param2" };
284287
HttpUrl url = RequestBuilder.constructHttpUrl("https://myserver.com/testservice/api", pathSegments, pathParameters);
285288
assertNotNull(url);
286-
assertNotEquals("https://myserver.com/testservice/api/v1/seg1/param1/seg2/param3/seg3", url);
289+
assertEquals("https://myserver.com/testservice/api/v1/seg1/param1/seg2/param2/seg3", url.toString());
287290
}
288291

289292
@Test
@@ -343,6 +346,132 @@ public void testConstructHttpUrlNull() {
343346
RequestBuilder.constructHttpUrl(null, pathSegments, pathParameters);
344347
}
345348

349+
@Test
350+
public void testResolveRequestUrlGood1() {
351+
Map<String, String> pathParameters = new HashMap<String, String>() {{
352+
put("param_1", "param1");
353+
put("param_2", "param2");
354+
}};
355+
356+
HttpUrl url = RequestBuilder.resolveRequestUrl(
357+
"https://myserver.com",
358+
"/v1/seg1/{param_1}/seg2/{param_2}/seg3",
359+
pathParameters);
360+
assertNotNull(url);
361+
assertEquals("https://myserver.com/v1/seg1/param1/seg2/param2/seg3", url.toString());
362+
}
363+
364+
@Test
365+
public void testResolveRequestUrlGood2() {
366+
Map<String, String> pathParameters = new HashMap<String, String>() {{
367+
put("param_1", "param1");
368+
put("param_2", "param2");
369+
}};
370+
371+
HttpUrl url = RequestBuilder.resolveRequestUrl(
372+
"https://myserver.com",
373+
"v1/seg1/{param_1}/seg2/{param_2}/seg3",
374+
pathParameters);
375+
assertNotNull(url);
376+
assertEquals("https://myserver.com/v1/seg1/param1/seg2/param2/seg3", url.toString());
377+
}
378+
379+
@Test
380+
public void testResolveRequestUrlGood3() {
381+
Map<String, String> pathParameters = new HashMap<String, String>() {{
382+
put("param_1", "param1");
383+
put("param_2", "param2");
384+
}};
385+
386+
HttpUrl url = RequestBuilder.resolveRequestUrl(
387+
"https://myserver.com/testservice/api",
388+
"/v1/seg1/{param_1}/seg2/{param_2}/seg3",
389+
pathParameters);
390+
assertNotNull(url);
391+
assertEquals("https://myserver.com/testservice/api/v1/seg1/param1/seg2/param2/seg3", url.toString());
392+
}
393+
394+
@Test
395+
public void testResolveRequestUrlGood4() {
396+
Map<String, String> pathParameters = new HashMap<String, String>() {{
397+
put("param_1", "param1");
398+
put("param_2", "param2");
399+
}};
400+
401+
HttpUrl url = RequestBuilder.resolveRequestUrl(
402+
"https://myserver.com/testservice/api",
403+
"v1/seg1/{param_1}/seg2/{param_2}/seg3",
404+
pathParameters);
405+
assertNotNull(url);
406+
assertEquals("https://myserver.com/testservice/api/v1/seg1/param1/seg2/param2/seg3", url.toString());
407+
}
408+
409+
@Test
410+
public void testResolveRequestUrlEmptyPath1() {
411+
HttpUrl url = RequestBuilder.resolveRequestUrl("https://myserver.com/testservice/api", "");
412+
assertNotNull(url);
413+
assertEquals("https://myserver.com/testservice/api", url.toString());
414+
}
415+
416+
@Test
417+
public void testResolveRequestUrlEmptyPath2() {
418+
HttpUrl url = RequestBuilder.resolveRequestUrl("https://myserver.com/testservice/api", null);
419+
assertNotNull(url);
420+
assertEquals("https://myserver.com/testservice/api", url.toString());
421+
}
422+
423+
@Test
424+
public void testResolveRequestUrlPathSlash1() {
425+
HttpUrl url = RequestBuilder.resolveRequestUrl("https://myserver.com/testservice/api", "/");
426+
assertNotNull(url);
427+
assertEquals("https://myserver.com/testservice/api/", url.toString());
428+
}
429+
430+
@Test
431+
public void testResolveRequestUrlPathSlash2() {
432+
HttpUrl url = RequestBuilder.resolveRequestUrl("https://myserver.com", "/");
433+
assertNotNull(url);
434+
assertEquals("https://myserver.com/", url.toString());
435+
}
436+
437+
@Test
438+
public void testResolveRequestUrlEncodedPathParams() {
439+
Map<String, String> pathParameters = new HashMap<String, String>() {{
440+
put("param_1", "param/1");
441+
put("param_2", "param 2");
442+
}};
443+
444+
HttpUrl url = RequestBuilder.resolveRequestUrl(
445+
"https://myserver.com",
446+
"/v1/seg1/{param_1}/seg2/{param_2}",
447+
pathParameters);
448+
assertNotNull(url);
449+
assertEquals("https://myserver.com/v1/seg1/param%2F1/seg2/param%202", url.toString());
450+
}
451+
452+
@Test(expected = IllegalArgumentException.class)
453+
public void testResolveRequestUrlEmptyPathParam() {
454+
Map<String, String> pathParameters = new HashMap<String, String>() {{
455+
put("param_1", "");
456+
put("param_2", "param2");
457+
}};
458+
459+
HttpUrl url = RequestBuilder.resolveRequestUrl(
460+
"https://myserver.com/testservice/api",
461+
"v1/seg1/{param_1}/seg2/{param_2}/seg3",
462+
pathParameters);
463+
}
464+
465+
@Test(expected = IllegalArgumentException.class)
466+
public void testResolveRequestUrlEmpty() {
467+
RequestBuilder.resolveRequestUrl("", "/");
468+
}
469+
470+
@Test(expected = IllegalArgumentException.class)
471+
public void testResolveRequestUrlNull() {
472+
RequestBuilder.resolveRequestUrl(null, "/");
473+
}
474+
346475
/**
347476
* Test bodyContent() with a model instance.
348477
* @throws IOException

0 commit comments

Comments
 (0)