In this post we are going to cover the main programming required to do this for free. For now it is up to you to tie this to a GUI for use / testing but I hope to release a custom component to wrap all of this up for easier use.
UPDATE: Here is a link to the custom component.
On the USPS website you can find the E-Commerce APIs. One of those is the Address Information API. If you want to test the code below out, you will need to ahead and create a USPS API account and then request access to the address standardization API. I recommend you do this upfront as it can sometimes take a couple of days to get access.
Note: this API is not meant for database cleaning but is instead meant for real time verification of addresses for items sent via USPS. You may also want to look at the Web Tools API Users Guide.
So lets start out with a class to hold all of our data:
public class USPSAddress {
// in the USPS world, address 1 contains address 2 data (i.e. UNIT 101 or APT A)
// So you will need to put the actual street address in address2 for proper parsing
public string Address1 {get; set;}
public string Address2 {get; set;}
public string City {get; set;}
public string State {get; set;}
public string Zip5 {get; set;}
public string Zip4 {get; set;}
public boolean USPS_Returned_Error {get; set;}
public string USPS_ERROR_CODE {get; set;}
public string USPS_ERROR_DESC {get; set;}
public string USPS_ERROR_SOURCE {get; set;}
public USPSAddress() {
Address1='';
Address2='';
City='';
State='';
Zip5='';
Zip4='';
USPS_Returned_Error = false;
USPS_ERROR_CODE = '';
USPS_ERROR_DESC = '';
USPS_ERROR_SOURCE = '';
} // constructor
public boolean HasData() {
// this will return false if everything was defaulted.
boolean ReturnValue = false;
if (Address1 !='') {
ReturnValue = true;
} else if (Address1 !='') {
ReturnValue = true;
} else if (Address2 !='') {
ReturnValue = true;
} else if (City !='') {
ReturnValue = true;
} else if (State !='') {
ReturnValue = true;
} else if (Zip5 !='') {
ReturnValue = true;
} else if (Zip4 !='') {
ReturnValue = true;
} else if (USPS_Returned_Error !=false) {
ReturnValue = true;
} else if (USPS_ERROR_CODE !='') {
ReturnValue = true;
} else if (USPS_ERROR_DESC !='') {
ReturnValue = true;
} else if (USPS_ERROR_SOURCE !='') {
ReturnValue = true;
}
return ReturnValue;
} // HasData
} // class USPSAddress
The code for the main class (including the test request #1 example) be sure to change your USER ID before using. Also, you will need to change the URL for initial testing and then back again for production access.
public with sharing class USPS {
private static final string USPS_UID = '<!-- INSERT YOUR ID HERE -->';
private static string BuildAddressQueryURLString(USPSAddress AddressToQuery) {
// this function is coded to send only one address at a time
// but it could be updated to support more (10 is the max ATM) by
// iterating over addresses and incremending the address ID XML for each address
// until you have one large URL as your query.
// However, if you do modify this for mutiple addresses then you will need to
// re-write the XML parse to handle that as well.
String BaseURL = 'http://production.shippingapis.com/ShippingAPI.dll?API=Verify&XML=';
String ReturnValue = '<AddressValidateRequest USERID="' + USPS_UID + '"><Address ID="0">';
ReturnValue += '<Address1>' + AddressToQuery.Address1 + '</Address1>';
ReturnValue += '<Address2>' + AddressToQuery.Address2 + '</Address2>';
ReturnValue += '<City>' + AddressToQuery.City + '</City>';
ReturnValue += '<State>' + AddressToQuery.State + '</State>';
ReturnValue += '<Zip5>' + AddressToQuery.Zip5 + '</Zip5>';
ReturnValue += '<Zip4>' + AddressToQuery.Zip4 + '</Zip4>';
ReturnValue += '</Address></AddressValidateRequest>';
ReturnValue = EncodingUtil.urlEncode(ReturnValue, 'UTF-8');
ReturnValue = BaseURL + ReturnValue;
return ReturnValue;
} // BuildAddressQueryURLString
private static string GetStandardizedAddressFromUSPS(string USPSURLtoQuery) {
string ReturnValue = '';
HttpRequest USPSRequest = new HttpRequest();
Http USPSHttp = new Http();
USPSRequest.setMethod('GET');
USPSRequest.setEndpoint(USPSURLtoQuery);
HttpResponse USPSResponse = USPSHttp.send(USPSRequest);
ReturnValue = USPSResponse.getBody();
system.debug('XML Response was: ' + ReturnValue);
system.debug('-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-');
return ReturnValue;
} // GetStandardizedAddressFromUSPS
private static USPSAddress ParseUSPSResponseXML(String XMLToParse) {
USPSAddress ReturnAddress = new USPSAddress();
// parse the response
XMLStreamReader USPSXMLReader = new XMLStreamReader(XMLToParse);
while (USPSXMLReader.hasNext()) {
if (USPSXMLReader.getEventType() == XmlTag.START_ELEMENT) {
if ('AddressValidateResponse' == USPSXMLReader.getLocalName()) {
USPSXMLReader.next();
if ('Address' == USPSXMLReader.getLocalName()) {
ReturnAddress = ParseUSPSAddressXML(USPSXMLReader);
} // <Address ID="0"> tag
} // <AddressValidateResponse> confirmation
} // Starting tag
USPSXMLReader.next();
} // loop thru UPS XML Reader
if (ReturnAddress.HasData() == false) {
// if parsing comes back totally blank then indicate an unknown / parsing error to the caller / requestor
system.Debug('ReturnAddress.HasData() == false');
ReturnAddress.USPS_Returned_Error = true;
ReturnAddress.USPS_ERROR_DESC = 'Unknown Error parsing XML Response';
ReturnAddress.USPS_ERROR_SOURCE = 'Salesforce XML Parsing';
ReturnAddress.USPS_ERROR_CODE = '-1';
} // ReturnAddress.HasData() == false
return ReturnAddress;
} // ParseAddressXML
private static USPSAddress ParseUSPSAddressXML(XMLStreamReader USPSAddressXMLReader) {
USPSAddress ReturnAddress = new USPSAddress();
while(USPSAddressXMLReader.hasNext()) {
if (USPSAddressXMLReader.getEventType() == XmlTag.END_ELEMENT) {
if ('Address' == USPSAddressXMLReader.getLocalName()) {
// quit parsing when we hit the end of this record
break;
} // check for address ending tag
} else if ('Error' == USPSAddressXMLReader.getLocalName()) {
system.Debug('API Returned an error!');
ReturnAddress = ParseUSPSErrorXML(USPSAddressXMLReader);
ReturnAddress.USPS_Returned_Error = true;
} else if ('Address1' == USPSAddressXMLReader.getLocalName()) {
USPSAddressXMLReader.next();
if (USPSAddressXMLReader.getEventType() == XmlTag.CHARACTERS) {
system.Debug('Address1: ' + USPSAddressXMLReader.getText());
ReturnAddress.Address1 = USPSAddressXMLReader.getText();
} // check for data
} else if ('Address2' == USPSAddressXMLReader.getLocalName()) {
USPSAddressXMLReader.next();
if (USPSAddressXMLReader.getEventType() == XmlTag.CHARACTERS) {
system.Debug('Address2: ' + USPSAddressXMLReader.getText());
ReturnAddress.Address2 = USPSAddressXMLReader.getText();
} // check for data
} else if ('City' == USPSAddressXMLReader.getLocalName()) {
USPSAddressXMLReader.next();
if (USPSAddressXMLReader.getEventType() == XmlTag.CHARACTERS) {
system.Debug('City: ' + USPSAddressXMLReader.getText());
ReturnAddress.City = USPSAddressXMLReader.getText();
} // check for data
} else if ('State' == USPSAddressXMLReader.getLocalName()) {
USPSAddressXMLReader.next();
if (USPSAddressXMLReader.getEventType() == XmlTag.CHARACTERS) {
system.Debug('State: ' + USPSAddressXMLReader.getText());
ReturnAddress.State = USPSAddressXMLReader.getText();
} // check for data
} else if ('Zip5' == USPSAddressXMLReader.getLocalName()) {
USPSAddressXMLReader.next();
if (USPSAddressXMLReader.getEventType() == XmlTag.CHARACTERS) {
system.Debug('Zip5: ' + USPSAddressXMLReader.getText());
ReturnAddress.Zip5 = USPSAddressXMLReader.getText();
} // check for data
} else if ('Zip4' == USPSAddressXMLReader.getLocalName()) {
USPSAddressXMLReader.next();
if (USPSAddressXMLReader.getEventType() == XmlTag.CHARACTERS) {
system.Debug('Zip4: ' + USPSAddressXMLReader.getText());
ReturnAddress.Zip4 = USPSAddressXMLReader.getText();
} // check for data
} // check for end tags
USPSAddressXMLReader.next();
} // loop thru XML reader
return ReturnAddress;
} // ParseUSPSAddressXML
private static USPSAddress ParseUSPSErrorXML(XMLStreamReader USPSErrorXMLReader) {
USPSAddress ReturnAddress = new USPSAddress();
while(USPSErrorXMLReader.hasNext()) {
if (USPSErrorXMLReader.getEventType() == XmlTag.END_ELEMENT) {
if ('Error' == USPSErrorXMLReader.getLocalName()) {
// quit parsing when we hit the end of this record
break;
}
} else if ('Number' == USPSErrorXMLReader.getLocalName()) {
USPSErrorXMLReader.next();
if (USPSErrorXMLReader.getEventType() == XmlTag.CHARACTERS) {
system.Debug('Error Number / Code: ' + USPSErrorXMLReader.getText());
ReturnAddress.USPS_ERROR_CODE = USPSErrorXMLReader.getText();
} // check for data
} else if ('Source' == USPSErrorXMLReader.getLocalName()) {
USPSErrorXMLReader.next();
if (USPSErrorXMLReader.getEventType() == XmlTag.CHARACTERS) {
system.Debug('Error Source: ' + USPSErrorXMLReader.getText());
ReturnAddress.USPS_ERROR_SOURCE = USPSErrorXMLReader.getText();
} // check for data
} else if ('Description' == USPSErrorXMLReader.getLocalName()) {
USPSErrorXMLReader.next();
if (USPSErrorXMLReader.getEventType() == XmlTag.CHARACTERS) {
system.Debug('Error Description: ' + USPSErrorXMLReader.getText());
ReturnAddress.USPS_ERROR_DESC = USPSErrorXMLReader.getText();
} // check for data
} // check for ending element
USPSErrorXMLReader.next();
} // loop thru XML reader
return ReturnAddress;
} // ParseUSPSErrorXML
public static USPSAddress CheckAddress(USPSAddress Address2Check) {
USPSAddress ResponseAddress = new USPSAddress();
// build the URL for the API call
string USPSURL = BuildAddressQueryURLString(Address2Check);
// call the API and pullback the XML as a string
string XMLResponse = GetStandardizedAddressFromUSPS(USPSURL);
// send the XML reponse to the parser
ResponseAddress = ParseUSPSResponseXML(XMLResponse);
return ResponseAddress;
} // CheckAddress
public static void RunUSPSTest1() {
// create a new object to hold the data
USPSAddress TestAddress = new USPSAddress();
// populate the data
TestAddress.Address2='6406 Ivy Lane';
TestAddress.City='Greenbelt';
TestAddress.State='MD';
USPSAddress SearchResult = CheckAddress(TestAddress);
} // Run USPS Test1
} // end USPS Class
No comments:
Post a Comment