From 70c5a4f289f3e8752dc05bdd02a671e54e722782 Mon Sep 17 00:00:00 2001 From: Justintime50 <39606064+Justintime50@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:32:33 -0700 Subject: [PATCH 1/2] feat: add a generic API request interface Co-Authored-By: Claude Sonnet 4.5 --- .../com/easypost/service/EasyPostClient.java | 23 +++++ src/test/cassettes/client/make_api_call.json | 88 +++++++++++++++++++ .../java/com/easypost/EasyPostClientTest.java | 50 +++++++++++ 3 files changed, 161 insertions(+) create mode 100644 src/test/cassettes/client/make_api_call.json create mode 100644 src/test/java/com/easypost/EasyPostClientTest.java diff --git a/src/main/java/com/easypost/service/EasyPostClient.java b/src/main/java/com/easypost/service/EasyPostClient.java index 8b21287f9..2e6b72b9f 100644 --- a/src/main/java/com/easypost/service/EasyPostClient.java +++ b/src/main/java/com/easypost/service/EasyPostClient.java @@ -1,13 +1,17 @@ package com.easypost.service; +import java.util.Map; import java.util.function.Function; import com.easypost.Constants; +import com.easypost.exception.EasyPostException; import com.easypost.exception.General.MissingParameterError; import com.easypost.hooks.RequestHook; import com.easypost.hooks.RequestHookResponses; import com.easypost.hooks.ResponseHook; import com.easypost.hooks.ResponseHookResponses; +import com.easypost.http.Requestor; +import com.easypost.http.Requestor.RequestMethod; import lombok.Getter; @@ -215,4 +219,23 @@ public String getApiVersion() { public String getApiBase() { return apiBase; } + + /** + * Make an API call to the EasyPost API. + * + * This public, generic interface is useful for making arbitrary API calls to the EasyPost API that + * are not yet supported by the client library's services. When possible, the service for your use case + * should be used instead as it provides a more convenient and higher-level interface depending on the endpoint. + * + * @param method The HTTP method to use for the request. + * @param endpoint The endpoint to call (e.g., "/addresses"). + * @param params The parameters to send with the request. + * @return A Map containing the API response. + * @throws EasyPostException when the request fails. + */ + @SuppressWarnings("unchecked") + public Map makeApiCall(RequestMethod method, String endpoint, Map params) + throws EasyPostException { + return Requestor.request(method, endpoint, params, Map.class, this); + } } diff --git a/src/test/cassettes/client/make_api_call.json b/src/test/cassettes/client/make_api_call.json new file mode 100644 index 000000000..29ee12a76 --- /dev/null +++ b/src/test/cassettes/client/make_api_call.json @@ -0,0 +1,88 @@ +[ + { + "recordedAt": 1770917472, + "request": { + "body": "", + "method": "GET", + "headers": { + "Accept-Charset": [ + "UTF-8" + ], + "User-Agent": [ + "REDACTED" + ] + }, + "uri": "https://api.easypost.com/v2/addresses?%70%61%67%65%5F%73%69%7A%65\u003d%31" + }, + "response": { + "body": "{\n \"addresses\": [\n {\n \"zip\": \"00001\",\n \"country\": \"US\",\n \"city\": \"NOT A CITY\",\n \"created_at\": \"2025-11-07T18:29:36Z\",\n \"verifications\": {\n \"delivery\": {\n \"success\": true,\n \"details\": {\n \"latitude\": null,\n \"time_zone\": null,\n \"longitude\": null\n },\n \"errors\": [\n {\n \"code\": \"E.ADDRESS.NOT_FOUND\",\n \"field\": \"address\",\n \"suggestion\": null,\n \"message\": \"Address not found\"\n }\n ]\n },\n \"verify_carrier\": \"ups\",\n \"zip4\": {\n \"success\": true,\n \"details\": null,\n \"errors\": [\n {\n \"code\": \"E.ADDRESS.NOT_FOUND\",\n \"field\": \"address\",\n \"suggestion\": null,\n \"message\": \"Address not found\"\n }\n ]\n }\n },\n \"mode\": \"test\",\n \"federal_tax_id\": null,\n \"state_tax_id\": null,\n \"carrier_facility\": null,\n \"residential\": null,\n \"updated_at\": \"2025-11-07T18:29:36Z\",\n \"phone\": \"REDACTED\",\n \"name\": null,\n \"company\": \"EASYPOST\",\n \"street1\": \"000 UNKNOWN STREET\",\n \"id\": \"adr_b6c1cfd0bc0711f0ac45ac1f6bc539ae\",\n \"street2\": null,\n \"state\": \"ZZ\",\n \"email\": \"TEST@EXAMPLE.COM\",\n \"object\": \"Address\"\n }\n ],\n \"has_more\": true\n}", + "httpVersion": null, + "headers": { + "null": [ + "HTTP/1.1 200 OK" + ], + "content-length": [ + "842" + ], + "expires": [ + "0" + ], + "x-node": [ + "bigweb53nuq" + ], + "x-frame-options": [ + "SAMEORIGIN" + ], + "x-download-options": [ + "noopen" + ], + "x-permitted-cross-domain-policies": [ + "none" + ], + "x-backend": [ + "easypost" + ], + "pragma": [ + "no-cache" + ], + "strict-transport-security": [ + "max-age\u003d31536000; includeSubDomains; preload" + ], + "x-xss-protection": [ + "1; mode\u003dblock" + ], + "x-content-type-options": [ + "nosniff" + ], + "x-ep-request-uuid": [ + "f785caef698e0e60e787ccbd0122bf10" + ], + "x-proxied": [ + "intlb5nuq 0dcc3a6efb", + "extlb2nuq c01291cd8f" + ], + "referrer-policy": [ + "strict-origin-when-cross-origin" + ], + "x-runtime": [ + "0.039820" + ], + "content-type": [ + "application/json; charset\u003dutf-8" + ], + "x-version-label": [ + "easypost-202602121702-bfe72e7ac7-master" + ], + "cache-control": [ + "private, no-cache, no-store" + ] + }, + "status": { + "code": 200, + "message": "OK" + }, + "uri": "https://api.easypost.com/v2/addresses?%70%61%67%65%5F%73%69%7A%65\u003d%31" + }, + "duration": 238 + } +] \ No newline at end of file diff --git a/src/test/java/com/easypost/EasyPostClientTest.java b/src/test/java/com/easypost/EasyPostClientTest.java new file mode 100644 index 000000000..305721a88 --- /dev/null +++ b/src/test/java/com/easypost/EasyPostClientTest.java @@ -0,0 +1,50 @@ +package com.easypost; + +import com.easypost.exception.EasyPostException; +import com.easypost.http.Requestor.RequestMethod; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public final class EasyPostClientTest { + private static TestUtils.VCR vcr; + + /** + * Set up the testing environment for this file. + * + * @throws EasyPostException when the request fails. + */ + @BeforeAll + public static void setup() throws EasyPostException { + vcr = new TestUtils.VCR("client", TestUtils.ApiKey.TEST); + } + + /** + * Test making a generic API call. + * + * @throws EasyPostException when the request fails. + */ + @Test + public void testMakeApiCall() throws EasyPostException { + vcr.setUpTest("make_api_call"); + + Map params = new HashMap<>(); + params.put("page_size", 1); + + Map response = vcr.client.makeApiCall(RequestMethod.GET, "addresses", params); + + assertNotNull(response); + List addresses = (List) response.get("addresses"); + assertNotNull(addresses); + assertEquals(1, addresses.size()); + + Map firstAddress = (Map) addresses.get(0); + assertEquals("Address", firstAddress.get("object")); + } +} From 4a12377e289f4bb0e7cd0c8843f91fab576f3e55 Mon Sep 17 00:00:00 2001 From: Justintime50 <39606064+Justintime50@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:43:30 -0700 Subject: [PATCH 2/2] chore: cleanup --- .../java/com/easypost/EasyPostClientTest.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/easypost/EasyPostClientTest.java b/src/test/java/com/easypost/EasyPostClientTest.java index 305721a88..369fa1332 100644 --- a/src/test/java/com/easypost/EasyPostClientTest.java +++ b/src/test/java/com/easypost/EasyPostClientTest.java @@ -1,16 +1,16 @@ package com.easypost; -import com.easypost.exception.EasyPostException; -import com.easypost.http.Requestor.RequestMethod; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.HashMap; import java.util.List; import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import com.easypost.exception.EasyPostException; +import com.easypost.http.Requestor.RequestMethod; public final class EasyPostClientTest { private static TestUtils.VCR vcr; @@ -39,11 +39,8 @@ public void testMakeApiCall() throws EasyPostException { Map response = vcr.client.makeApiCall(RequestMethod.GET, "addresses", params); - assertNotNull(response); List addresses = (List) response.get("addresses"); - assertNotNull(addresses); assertEquals(1, addresses.size()); - Map firstAddress = (Map) addresses.get(0); assertEquals("Address", firstAddress.get("object")); }