diff --git a/examples/international_postal_code.mjs b/examples/international_postal_code.mjs
new file mode 100644
index 0000000..f78f9c2
--- /dev/null
+++ b/examples/international_postal_code.mjs
@@ -0,0 +1,70 @@
+import SmartySDK from "smartystreets-javascript-sdk";
+
+const SmartyCore = SmartySDK.core;
+const Lookup = SmartySDK.internationalPostalCode.Lookup;
+
+// for Server-to-server requests, use this code:
+// let authId = process.env.SMARTY_AUTH_ID;
+// let authToken = process.env.SMARTY_AUTH_TOKEN;
+// const credentials = new SmartyCore.StaticCredentials(authId, authToken);
+
+// for client-side requests (browser/mobile), use this code:
+let key = process.env.SMARTY_EMBEDDED_KEY;
+const credentials = new SmartyCore.SharedCredentials(key);
+
+// The appropriate license values to be used for your subscriptions
+// can be found on the Subscription page of the account dashboard.
+// https://www.smarty.com/docs/cloud/licensing
+let clientBuilder = new SmartyCore.ClientBuilder(credentials);
+// .withBaseUrl("YOUR URL") // withBaseUrl() should be used if you are self-hosting the Smarty API
+let client = clientBuilder.buildInternationalPostalCodeClient();
+
+// Documentation for input fields can be found at:
+// https://www.smarty.com/docs/cloud/international-postal-code-api#input-fields
+
+// Lookup by postal code and country
+let lookup1 = new Lookup("Australia", "2776");
+// uncomment the following line to add a custom parameter
+// lookup1.addCustomParameter("input_id", 1234);
+
+// Lookup by locality, administrative area, and country
+let lookup2 = new Lookup("Brazil", null, "SP", "Sao Paulo", "ID-8675309");
+
+await handleResponse(lookup1, "Postal code lookup");
+await handleResponse(lookup2, "Locality and administrative area lookup");
+
+function displayResult(lookup, message) {
+ console.log("*** " + message + " ***");
+ if (lookup.result && lookup.result.length > 0) {
+ lookup.result.forEach((result) => {
+ console.log("Input ID:", result.inputId);
+ console.log("Administrative Area:", result.administrativeArea);
+ console.log("Super Administrative Area:", result.superAdministrativeArea);
+ console.log("Sub Administrative Area:", result.subAdministrativeArea);
+ console.log("Locality:", result.locality);
+ console.log("Dependent Locality:", result.dependentLocality);
+ console.log("Dependent Locality Name:", result.dependentLocalityName);
+ console.log("Double Dependent Locality:", result.doubleDependentLocality);
+ console.log("Postal Code:", result.postalCode);
+ console.log("Postal Code Extra:", result.postalCodeExtra);
+ console.log("Country ISO3:", result.countryIso3);
+ console.log("---");
+ });
+ } else {
+ console.log("No results found");
+ }
+ console.log("\n");
+}
+
+function handleError(error) {
+ console.log("ERROR:", error);
+}
+
+async function handleResponse(lookup, lookupType) {
+ try {
+ const result = await client.send(lookup);
+ displayResult(result, lookupType);
+ } catch (err) {
+ handleError(err);
+ }
+}
diff --git a/examples/us_zipcode.mjs b/examples/us_zipcode.mjs
index 0c521c6..b34633c 100644
--- a/examples/us_zipcode.mjs
+++ b/examples/us_zipcode.mjs
@@ -13,7 +13,7 @@ let key = process.env.SMARTY_EMBEDDED_KEY;
const credentials = new SmartyCore.SharedCredentials(key);
let clientBuilder = new SmartyCore.ClientBuilder(credentials);
- // .withBaseUrl("YOUR URL") // withBaseUrl() should be used if you are self-hosting the Smarty API
+// .withBaseUrl("YOUR URL") // withBaseUrl() should be used if you are self-hosting the Smarty API
let client = clientBuilder.buildUsZipcodeClient();
@@ -45,17 +45,19 @@ batch.add(lookup3);
await handleResponse(batch);
function viewResults(response) {
- response.lookups.map(lookup => lookup.result.map(candidate => {
- candidate.cities.map(city => console.log(city.city));
- // candidate.zipcodes.map(zipcode => console.log(zipcode.zipcode));
- }));
+ response.lookups.map((lookup) =>
+ lookup.result.map((candidate) => {
+ candidate.cities.map((city) => console.log(city.city));
+ // candidate.zipcodes.map(zipcode => console.log(zipcode.zipcode));
+ }),
+ );
}
async function handleResponse(lookup) {
try {
const result = await client.send(lookup);
viewResults(result);
- } catch(err) {
+ } catch (err) {
console.log(err);
}
-}
\ No newline at end of file
+}
diff --git a/index.mjs b/index.mjs
index 86312be..b45192c 100644
--- a/index.mjs
+++ b/index.mjs
@@ -32,6 +32,9 @@ import SuggestionInternationalAddressAutocomplete from "./src/international_addr
import LookupUSEnrichment from "./src/us_enrichment/Lookup.js";
import ResponseUSEnrichment from "./src/us_enrichment/Response.js";
+import LookupInternationalPostalCode from "./src/international_postal_code/Lookup.js";
+import ResultInternationalPostalCode from "./src/international_postal_code/Result.js";
+
export const core = {
Batch,
ClientBuilder,
@@ -80,6 +83,11 @@ export const usEnrichment = {
Response: ResponseUSEnrichment,
};
+export const internationalPostalCode = {
+ Lookup: LookupInternationalPostalCode,
+ Result: ResultInternationalPostalCode,
+};
+
export default {
core,
usStreet,
@@ -90,4 +98,5 @@ export default {
usReverseGeo,
internationalAddressAutocomplete,
usEnrichment,
+ internationalPostalCode,
};
diff --git a/src/ClientBuilder.js b/src/ClientBuilder.js
index 7b65178..ae30f31 100644
--- a/src/ClientBuilder.js
+++ b/src/ClientBuilder.js
@@ -20,6 +20,7 @@ const InternationalStreetClient = require("./international_street/Client");
const UsReverseGeoClient = require("./us_reverse_geo/Client");
const InternationalAddressAutocompleteClient = require("./international_address_autocomplete/Client");
const UsEnrichmentClient = require("./us_enrichment/Client");
+const InternationalPostalCodeClient = require("./international_postal_code/Client");
const INTERNATIONAL_STREET_API_URI = "https://international-street.api.smarty.com/verify";
const US_AUTOCOMPLETE_PRO_API_URL = "https://us-autocomplete-pro.api.smarty.com/lookup";
@@ -30,7 +31,7 @@ const US_REVERSE_GEO_API_URL = "https://us-reverse-geo.api.smarty.com/lookup";
const INTERNATIONAL_ADDRESS_AUTOCOMPLETE_API_URL =
"https://international-autocomplete.api.smarty.com/v2/lookup";
const US_ENRICHMENT_API_URL = "https://us-enrichment.api.smarty.com/lookup";
-
+const INTERNATIONAL_POSTAL_CODE_API_URL = "https://international-postal-code.api.smarty.com/lookup";
/**
* The ClientBuilder class helps you build a client object for one of the supported Smarty APIs.
* You can use ClientBuilder's methods to customize settings like maximum retries or timeout duration. These methods
@@ -51,7 +52,7 @@ class ClientBuilder {
this.licenses = [];
function noCredentialsProvided() {
- return !signer instanceof StaticCredentials || !signer instanceof SharedCredentials;
+ return (!signer) instanceof StaticCredentials || (!signer) instanceof SharedCredentials;
}
}
@@ -185,6 +186,10 @@ class ClientBuilder {
return this.buildClient(US_ZIP_CODE_API_URL, UsZipcodeClient);
}
+ buildInternationalPostalCodeClient() {
+ return this.buildClient(INTERNATIONAL_POSTAL_CODE_API_URL, InternationalPostalCodeClient);
+ }
+
buildUsAutocompleteProClient() {
return this.buildClient(US_AUTOCOMPLETE_PRO_API_URL, UsAutocompleteProClient);
}
@@ -213,4 +218,4 @@ class ClientBuilder {
}
}
-module.exports = ClientBuilder;
\ No newline at end of file
+module.exports = ClientBuilder;
diff --git a/src/international_postal_code/Client.js b/src/international_postal_code/Client.js
new file mode 100644
index 0000000..22ed7c3
--- /dev/null
+++ b/src/international_postal_code/Client.js
@@ -0,0 +1,49 @@
+const Request = require("../Request");
+const Result = require("./Result");
+const buildInputData = require("../util/buildInputData");
+const keyTranslationFormat = require("../util/apiToSDKKeyMap").internationalPostalCode;
+const { UndefinedLookupError } = require("../Errors");
+
+/**
+ * This client sends lookups to the Smarty International Postal Code API,
+ * and attaches the results to the appropriate Lookup objects.
+ */
+class Client {
+ constructor(sender) {
+ this.sender = sender;
+ }
+
+ /**
+ * Sends a single lookup for validation.
+ * @param data A Lookup object
+ * @throws SmartyException
+ */
+ send(lookup) {
+ if (typeof lookup === "undefined") throw new UndefinedLookupError();
+
+ let request = new Request();
+ request.parameters = buildInputData(lookup, keyTranslationFormat);
+
+ return new Promise((resolve, reject) => {
+ this.sender
+ .send(request)
+ .then((response) => {
+ if (response.error) reject(response.error);
+
+ resolve(attachLookupResults(response, lookup));
+ })
+ .catch(reject);
+ });
+
+ function attachLookupResults(response, lookup) {
+ if (response.payload && Array.isArray(response.payload)) {
+ lookup.result = response.payload.map((r) => new Result(r));
+ } else {
+ lookup.result = [];
+ }
+ return lookup;
+ }
+ }
+}
+
+module.exports = Client;
diff --git a/src/international_postal_code/Lookup.js b/src/international_postal_code/Lookup.js
new file mode 100644
index 0000000..a205418
--- /dev/null
+++ b/src/international_postal_code/Lookup.js
@@ -0,0 +1,22 @@
+/**
+ * In addition to holding all of the input data for this lookup, this class also
+ * will contain the result of the lookup after it comes back from the API.
+ * @see "https://www.smarty.com/docs/cloud/international-postal-code-api#http-request-input-fields"
+ */
+class Lookup {
+ constructor(country, postalCode, administrativeArea, locality, inputId) {
+ this.inputId = inputId;
+ this.country = country;
+ this.postalCode = postalCode;
+ this.administrativeArea = administrativeArea;
+ this.locality = locality;
+ this.result = [];
+ this.customParameters = {};
+ }
+
+ addCustomParameter(key, value) {
+ this.customParameters[key] = value;
+ }
+}
+
+module.exports = Lookup;
diff --git a/src/international_postal_code/Result.js b/src/international_postal_code/Result.js
new file mode 100644
index 0000000..ccfa723
--- /dev/null
+++ b/src/international_postal_code/Result.js
@@ -0,0 +1,20 @@
+/**
+ * @see "https://www.smarty.com/docs/cloud/international-postal-code-api#output-fields"
+ */
+class Result {
+ constructor(responseData) {
+ this.inputId = responseData.input_id;
+ this.administrativeArea = responseData.administrative_area;
+ this.superAdministrativeArea = responseData.super_administrative_area;
+ this.subAdministrativeArea = responseData.sub_administrative_area;
+ this.locality = responseData.locality;
+ this.dependentLocality = responseData.dependent_locality;
+ this.dependentLocalityName = responseData.dependent_locality_name;
+ this.doubleDependentLocality = responseData.double_dependent_locality;
+ this.postalCode = responseData.postal_code;
+ this.postalCodeExtra = responseData.postal_code_extra;
+ this.countryIso3 = responseData.country_iso_3;
+ }
+}
+
+module.exports = Result;
diff --git a/src/util/apiToSDKKeyMap.js b/src/util/apiToSDKKeyMap.js
index bc370ae..ea947c5 100644
--- a/src/util/apiToSDKKeyMap.js
+++ b/src/util/apiToSDKKeyMap.js
@@ -72,5 +72,12 @@ module.exports = {
exclude: "exclude",
dataset: "dataset",
data_subset: "dataSubset",
+ },
+ internationalPostalCode: {
+ "input_id": "inputId",
+ "country": "country",
+ "locality": "locality",
+ "administrative_area": "administrativeArea",
+ "postal_code": "postalCode",
}
};
\ No newline at end of file
diff --git a/src/util/buildClients.js b/src/util/buildClients.js
index 42441f2..3e84776 100644
--- a/src/util/buildClients.js
+++ b/src/util/buildClients.js
@@ -36,6 +36,10 @@ function buildUsEnrichmentApiClient(credentials) {
return instantiateClientBuilder(credentials).buildUsEnrichmentClient();
}
+function buildInternationalPostalCodeApiClient(credentials) {
+ return instantiateClientBuilder(credentials).buildInternationalPostalCodeClient();
+}
+
module.exports = {
usStreet: buildUsStreetApiClient,
usAutocompletePro: buildUsAutocompleteProApiClient,
@@ -45,4 +49,5 @@ module.exports = {
usReverseGeo: buildUsReverseGeoApiClient,
internationalAddressAutocomplete: buildInternationalAddressAutocompleteApiClient,
usEnrichment: buildUsEnrichmentApiClient,
+ internationalPostalCode: buildInternationalPostalCodeApiClient,
};
\ No newline at end of file
diff --git a/tests/international_postal_code/test_Client.js b/tests/international_postal_code/test_Client.js
new file mode 100644
index 0000000..0d79d67
--- /dev/null
+++ b/tests/international_postal_code/test_Client.js
@@ -0,0 +1,68 @@
+const chai = require("chai");
+const expect = chai.expect;
+const Client = require("../../src/international_postal_code/Client");
+const Lookup = require("../../src/international_postal_code/Lookup");
+const MockSender = require("../fixtures/mock_senders").MockSender;
+const MockSenderWithResponse = require("../fixtures/mock_senders").MockSenderWithResponse;
+
+describe("An International Postal Code client", function () {
+ it("has an inner sender.", function () {
+ let mockSender = new MockSender();
+ let client = new Client(mockSender);
+
+ expect(client.sender).to.deep.equal(mockSender);
+ });
+
+ it("throws an error if sending without a lookup.", function () {
+ let mockSender = new MockSender();
+ let client = new Client(mockSender);
+
+ expect(() => client.send()).to.throw();
+ });
+
+ it("attaches a result from a response to a lookup.", function () {
+ const expectedMockPayload = [
+ {
+ input_id: "1234",
+ administrative_area: "SP",
+ super_administrative_area: undefined,
+ sub_administrative_area: undefined,
+ locality: "São Paulo",
+ dependent_locality: "Casa Verde",
+ dependent_locality_name: undefined,
+ double_dependent_locality: undefined,
+ postal_code: "02516-040",
+ postal_code_extra: undefined,
+ country_iso_3: "BRA",
+ },
+ ];
+ let mockSender = new MockSenderWithResponse(expectedMockPayload);
+ const client = new Client(mockSender);
+ let lookup = new Lookup("Brazil", "02516-040");
+
+ return client.send(lookup).then(() => {
+ expect(lookup.result).to.be.an("array");
+ expect(lookup.result.length).to.equal(1);
+ expect(lookup.result[0].inputId).to.equal("1234");
+ expect(lookup.result[0].administrativeArea).to.equal("SP");
+ expect(lookup.result[0].locality).to.equal("São Paulo");
+ expect(lookup.result[0].dependentLocality).to.equal("Casa Verde");
+ expect(lookup.result[0].postalCode).to.equal("02516-040");
+ expect(lookup.result[0].countryIso3).to.equal("BRA");
+ });
+ });
+
+ it("handles empty results array.", function () {
+ const expectedMockPayload = {
+ results: [],
+ };
+ let mockSender = new MockSenderWithResponse(expectedMockPayload);
+ const client = new Client(mockSender);
+ let lookup = new Lookup("Brazil", "99999-999");
+
+ return client.send(lookup).then(() => {
+ expect(lookup.result).to.be.an("array");
+ expect(lookup.result.length).to.equal(0);
+ });
+ });
+});
diff --git a/tests/international_postal_code/test_Lookup.js b/tests/international_postal_code/test_Lookup.js
new file mode 100644
index 0000000..94367db
--- /dev/null
+++ b/tests/international_postal_code/test_Lookup.js
@@ -0,0 +1,24 @@
+const chai = require("chai");
+const expect = chai.expect;
+const Lookup = require("../../src/international_postal_code/Lookup");
+
+describe("An International Postal Code lookup", function () {
+ it("correctly populates fields.", function () {
+ let lookup = new Lookup("Brazil", "02516-040", "SP", "Sao Paulo", "1234");
+
+ expect(lookup.inputId).to.equal("1234");
+ expect(lookup.country).to.equal("Brazil");
+ expect(lookup.postalCode).to.equal("02516-040");
+ expect(lookup.administrativeArea).to.equal("SP");
+ expect(lookup.locality).to.equal("Sao Paulo");
+ expect(lookup.result).to.deep.equal([]);
+ expect(lookup.customParameters).to.deep.equal({});
+ });
+
+ it("can add custom parameters.", function () {
+ let lookup = new Lookup("Brazil", "02516-040");
+ lookup.addCustomParameter("test", "value");
+
+ expect(lookup.customParameters.test).to.equal("value");
+ });
+});
diff --git a/tests/international_postal_code/test_Result.js b/tests/international_postal_code/test_Result.js
new file mode 100644
index 0000000..bc873de
--- /dev/null
+++ b/tests/international_postal_code/test_Result.js
@@ -0,0 +1,54 @@
+const chai = require("chai");
+const expect = chai.expect;
+const Result = require("../../src/international_postal_code/Result");
+
+describe("An International Postal Code result", function () {
+ it("populates with the appropriate fields.", function () {
+ const sampleResponse = {
+ input_id: "1234",
+ administrative_area: "SP",
+ super_administrative_area: "Southeast",
+ sub_administrative_area: "Metropolitan",
+ locality: "São Paulo",
+ dependent_locality: "Casa Verde",
+ dependent_locality_name: "Casa Verde District",
+ double_dependent_locality: "Zone 1",
+ postal_code: "02516-040",
+ postal_code_extra: "12345",
+ country_iso_3: "BRA",
+ };
+
+ const result = new Result(sampleResponse);
+
+ expect(result.inputId).to.equal("1234");
+ expect(result.administrativeArea).to.equal("SP");
+ expect(result.superAdministrativeArea).to.equal("Southeast");
+ expect(result.subAdministrativeArea).to.equal("Metropolitan");
+ expect(result.locality).to.equal("São Paulo");
+ expect(result.dependentLocality).to.equal("Casa Verde");
+ expect(result.dependentLocalityName).to.equal("Casa Verde District");
+ expect(result.doubleDependentLocality).to.equal("Zone 1");
+ expect(result.postalCode).to.equal("02516-040");
+ expect(result.postalCodeExtra).to.equal("12345");
+ expect(result.countryIso3).to.equal("BRA");
+ });
+
+ it("handles missing optional fields.", function () {
+ const sampleResponse = {
+ administrative_area: "SP",
+ locality: "São Paulo",
+ postal_code: "02516-040",
+ country_iso_3: "BRA",
+ };
+
+ const result = new Result(sampleResponse);
+
+ expect(result.inputId).to.equal(undefined);
+ expect(result.superAdministrativeArea).to.equal(undefined);
+ expect(result.postalCodeExtra).to.equal(undefined);
+ expect(result.administrativeArea).to.equal("SP");
+ expect(result.locality).to.equal("São Paulo");
+ expect(result.postalCode).to.equal("02516-040");
+ expect(result.countryIso3).to.equal("BRA");
+ });
+});