The service program extract below contains a few subprocedures used to validate a given city/state/zip combination using HTTPAPI to access the UPS Web Services.  You will need to get a UPS username and account, and apply for a developer access key.  A good page to start learning about what is available and how to get started is here.

Overview of code structure:

  • Near the top is a group of global D-Specs that would normally be in a copy source for production use to allow them to be easily added to any program that needs to call the exported subprocedures.
  • The service program has some local subprocedures to handle the parsing of the returned information from the UPS web service.  These are referenced by procedure pointers used in the HTTPAPI call.  
  • For each UPS service you add to the service program, it would have it's own pair of start and end procedures to handle the parsing.

For now, I will just post the code and can expand more on this write-up if people have questions.

 

     H NOMAIN OPTION(*SRCSTMT:*NODEBUGIO:*NOUNREF:*NOSHOWCPY) DEBUG(*YES)
     H BNDDIR('QC2LE':'HTTPAPI')

      //----------------------------------------------------------------
      //  PROGRAM NAME.. UPS Web Services
      //
      //  DESCRIPTION... Collection of procedures to handle various
      //                 online interactions with UPS.  There will be
      //                 exported procedures for primary services and
      //                 non-exported procedures that support those
      //                 primary services soley in this service program.
      //----------------------------------------------------------------

      // Cels D Specs & HTTPAPI
      //include CECOPYSRC,CELSDSPECS
      /include LIBHTTP/QRPGLESRC,HTTPAPI_H

      // D-Specs for this Service Program (would usually be in a copy source
      //   to make sharing of the exported procedures simpler.  Included
      //   inline in this example code.

      //--------------------------------------------------------------------
      //  Procedure: UPS Web Services D-Specs
      //  Date.....: 09/22/11
      //  Author...: David Wright
      //----------------------------------------------------------------

      // Misc constants used below
     D true            c                   *on
     D false           c                   *off
     D Upper           c                   'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
     D Lower           c                   'abcdefghijklmnopqrstuvwxyz'

      // UPS Account Info
     D UPS_USERID      c                   'username'
     D UPS_PASSWD      c                   'password'
     D UPS_LICENSE     c                   'UpsDeveloperKey '

      // City,State,Zip Data Structure
     D l_UpsCSZds      ds                  template qualified
     d  iRank                         2s 0
     d  fQuality                      7s 4
     D  sCity                        20a
     D  sState                        2a
     D  sZipLow                       5a
     D  sZipHigh                      5a

     D l_UpsCSZHdrDs   ds                  inz qualified
     D  iRanks                        5u 0
     D  sStatus                       1a
     D  sError                       50a
     D  dsCsz                              likeds(l_UpsCSZds) dim(20)


      //--------------------------------------------------------------------
      //  Procedure: Validate City State Zip with UPS
      //  Proc Name: IsValidCSZ
      //  Date.....: 09/22/11
      //  Author...: David Wright
      //----------------------------------------------------------------
     DIsValidCSZ       pr              n
     D  sCity                        40a   const
     D  sState                        2a   const
     D  sZip                          9a   const


      //--------------------------------------------------------------------
      //  Procedure: Get City State Zip Options from UPS
      //  Proc Name: GetCityStateZip
      //  Date.....: 09/22/11
      //  Author...: David Wright
      //----------------------------------------------------------------
     DGetCityStateZip  pr                  likeds(l_UpsCSZHdrDs)
     D  sCity                        40a   const
     D  sState                        2a   const
     D  sZip                          9a   const
     D  p#ptrLines                     *   const options(*nopass)



      //--------------------------------------------------------------------
      //  Procedure: Cleanup Address Elements to UPS Standards
      //  Proc Name: CleanupUpsAddr
      //  Date.....: 09/22/11
      //  Author...: David Wright
      //----------------------------------------------------------------
     DCleanupUpsAddr   pr            50a
     D  sIn                          50a   const



      //--------------------------------------------------------------------
      //  Procedure: Validate City State Zip with UPS
      //  Proc Name: IsValidCSZ
      //  Date.....: 09/22/11
      //  Author...: David Wright
      //----------------------------------------------------------------
      // USAGE NOTE:  Parms are NOT constant.  Values could be corrected
      //----------------------------------------------------------------
      //  Modification Control.
      //  ~~~~~~~~~~~~~~~~~~~~~
      //   Code    By     Date    Description
      //   ~~~~    ~~     ~~~~    ~~~~~~~~~~~
      //  25632    DW    9/22/11  * Initial release
      //----------------------------------------------------------------
     PIsValidCSZ       b                   export
     DIsValidCSZ       pi              n
     D  p#sCity                      40a   const
     D  p#sState                      2a   const
     D  p#sZip                        9a   const

      // Work Data Structure
     D dsOptions       ds                  inz likeds(l_UpsCSZHdrDs)

      // Work Variables
     D  sCity          s             40a   inz
     D  sState         s              2a   inz
     D  sZip           s              9a   inz
      /free
       // Use parms
         sCity = CleanupUpsAddr(p#sCity);
         sState = CleanupUpsAddr(p#sState);
         sZip = CleanupUpsAddr(p#sZip);

       // Get CSZ Options
         dsOptions = GetCityStateZip(sCity: sState: sZip);

       // If they match option 1, then if is valid
         return ((dsOptions.dsCsz(1).fQuality = 1) and
                 (sCity = dsOptions.dsCsz(1).sCity) and
                 (sState = dsOptions.dsCsz(1).sState) and
                 (sZip >= dsOptions.dsCsz(1).sZipLow) and
                 (sZip <= dsOptions.dsCsz(1).sZipHigh));
      /end-free
     PIsValidCSZ       e


      //--------------------------------------------------------------------
      //  Procedure: Get City State Zip Options from UPS
      //  Proc Name: GetCityStateZip
      //  Date.....: 09/22/11
      //  Author...: David Wright
      //----------------------------------------------------------------
      //  Modification Control.
      //  ~~~~~~~~~~~~~~~~~~~~~
      //   Code    By     Date    Description
      //   ~~~~    ~~     ~~~~    ~~~~~~~~~~~
      //  25632    DW    9/22/11  * Initial release
      //----------------------------------------------------------------
     PGetCityStateZip  b                   export
     DGetCityStateZip  pi                  likeds(l_UpsCSZHdrDs)
     D  p#sCity                      40a   const
     D  p#sState                      2a   const
     D  p#sZip                        9a   const
     D  p#ptrLines                     *   const options(*nopass)

      // HTTP Vars
     D rc              s             10I 0
     D postData        s            750A   varying

      // Work Data Structure
     D dsOptions       ds                  inz likeds(l_UpsCSZHdrDs)

      // Misc Work Variables
     D ptrLines        s               *
     D  sCity          s             40a   inz
     D  sState         s              2a   inz
     D  sZip           s              9a   inz
      /free
       // Use parms
         sCity = p#sCity;
         sState = p#sState;
         sZip = p#sZip;

       // Cleanup Addresses
         sCity = CleanupUpsAddr(sCity);
         sState = CleanupUpsAddr(sState);
         sZip = CleanupUpsAddr(sZip);

       // Use lines pointer if passed
         if %parms = 4;
           ptrLines = p#ptrLines;
         endif;

       // Build Request
         postData =
         '<?xml version="1.0"?>'                                      +
         '<AccessRequest>'                                            +
            '<AccessLicenseNumber>' + UPS_LICENSE + '</AccessLicenseNumber>' +
            '<UserId>' + UPS_USERID + '</UserId>'                     +
            '<Password>' + UPS_PASSWD + '</Password>'                 +
         '</AccessRequest>'                                           +
         '<?xml version="1.0"?>'                                      +
         '<AddressValidationRequest xml:lang="en-US">'                +
            '<Request>'                                               +
               '<TransactionReference>'                               +
                  '<CustomerContext>CELS Enterprises Inc.</CustomerContext>' +
                  '<XpciVersion>1.0001</XpciVersion>'                 +
               '</TransactionReference>'                              +
               '<RequestAction>AV</RequestAction>'                    +
            '</Request>'                                              +
            '<Address>'                                               +
              '<City>' + %trim(sCity) + '</City>'                     +
              '<StateProvinceCode>' + sState + '</StateProvinceCode>' +
              '<PostalCode>' + sZip + '</PostalCode>'                 +
            '</Address>'                                              +
         '</AddressValidationRequest>'                                ;

       // Send Request
         rc = http_url_post_xml('https://www.ups.com/ups.app/xml/AV'
                               : %addr(postData) + 2
                               : %len(postData)
                               : %paddr(StartGetCSZ)
                               : %paddr(EndGetCSZ)
                               : %addr(dsOptions));

       // Exit
         return dsOptions;
      /end-free
     PGetCityStateZip  e


      //--------------------------------------------------------------------
      //  Procedure: Get City State Zip Options from UPS - Start of Element
      //  Proc Name: StartGetCSZ
      //  Date.....: 09/22/11
      //  Author...: David Wright
      //----------------------------------------------------------------
      //  Modification Control.
      //  ~~~~~~~~~~~~~~~~~~~~~
      //   Code    By     Date    Description
      //   ~~~~    ~~     ~~~~    ~~~~~~~~~~~
      //  25632    DW    9/22/11  * Initial release
      //----------------------------------------------------------------
     PStartGetCSZ      b
     DStartGetCSZ      pi
     D  pUserData                      *   value
     D  iDepth                       10i 0 value
     D  sName                      1024a   varying const
     D  sPath                     24576a   varying const
     D  pAttrs                         *   dim(32767)
     D                                     const options(*varsize)

      // Work Data Structure
     D dsOptions       ds                  likeds(l_UpsCSZHdrDs)
     D                                     based(pUserData)
      /free
        if sName = 'Rank';
           dsOptions.iRanks += 1;
        endif;
      /end-free
     PStartGetCSZ      e


      //--------------------------------------------------------------------
      //  Procedure: Get City State Zip Options from UPS - End of Element
      //  Proc Name: EndGetCSZ
      //  Date.....: 09/22/11
      //  Author...: David Wright
      //----------------------------------------------------------------
      //  Modification Control.
      //  ~~~~~~~~~~~~~~~~~~~~~
      //   Code    By     Date    Description
      //   ~~~~    ~~     ~~~~    ~~~~~~~~~~~
      //  25632    DW    9/22/11  * Initial release
      //----------------------------------------------------------------
     PEndGetCSZ        b
     DEndGetCSZ        pi
     D  pUserData                      *   value
     D  iDepth                       10I 0 value
     D  sName                      1024A   varying const
     D  sPath                     24576A   varying const
     D  sValue                    32767A   varying const
     D  pAttrs                         *   dim(32767)
     D                                     const options(*varsize)

      // Work Data Structure
     D dsOptions       ds                  likeds(l_UpsCSZHdrDs)
     D                                     based(pUserData)
     D bNoRank         s               n   inz
      /free
       // If no ranks yet, position to first array element (which will be empty)
         if dsOptions.iRanks = 0;
           bNoRank = true;
           dsOptions.iRanks = 1;
         endif;

       select;
       when sPath = '/AddressValidationResponse/Response' and
            sName = 'ResponseStatusCode';
                 dsOptions.sStatus = sValue;
                 if  dsOptions.sStatus <> '1';
                     if  dsOptions.dsCsz(dsOptions.iRanks).sCity = *blanks;
                         dsOptions.sError = 'No Address Cadidate Found...';
                     else;
                         dsOptions.sError = 'No Address Cadidate Found for ' +
                           %trim(dsOptions.dsCsz(dsOptions.iRanks).sCity) +
                           ' ' + dsOptions.dsCsz(dsOptions.iRanks).sState;
                     endIf;
                 endIf;

       when sPath = '/AddressValidationResponse/AddressValidationResult'
             and sName = 'Rank' and dsOptions.sStatus = '1';
                 dsOptions.dsCsz(dsOptions.iRanks).iRank = %Dec(sValue:2:0);

       when sPath = '/AddressValidationResponse/AddressValidationResult' and
             sName = 'Quality' and dsOptions.sStatus = '1';
                 dsOptions.dsCsz(dsOptions.iRanks).fQuality = %Dec(sValue:7:4);

       when sPath = '/AddressValidationResponse/AddressValidationResult/Address'
             and sName = 'City' and dsOptions.sStatus = '1';
                 dsOptions.dsCsz(dsOptions.iRanks).sCity = sValue;

       when sPath = '/AddressValidationResponse/AddressValidationResult/Address'
             and sName = 'StateProvinceCode' and dsOptions.sStatus = '1';
                 dsOptions.dsCsz(dsOptions.iRanks).sState = sValue;

       when sPath = '/AddressValidationResponse/AddressValidationResult'
             and sName = 'PostalCodeLowEnd' and dsOptions.sStatus = '1';
                 dsOptions.dsCsz(dsOptions.iRanks).sZipLow = sValue;

       when sPath = '/AddressValidationResponse/AddressValidationResult'
             and sName = 'PostalCodeHighEnd' and dsOptions.sStatus = '1';
                 dsOptions.dsCsz(dsOptions.iRanks).sZipHigh = sValue;

       endsl;

       // If rank was faked, put back to zero
         if bNoRank;
           dsOptions.iRanks = 0;
         endif;

      /end-free
     PEndGetCSZ        e


      //--------------------------------------------------------------------
      //  Procedure: Cleanup Address Elements to UPS Standards
      //  Proc Name: CleanupUpsAddr
      //  Date.....: 09/22/11
      //  Author...: David Wright
      //----------------------------------------------------------------
      //  Modification Control.
      //  ~~~~~~~~~~~~~~~~~~~~~
      //   Code    By     Date    Description
      //   ~~~~    ~~     ~~~~    ~~~~~~~~~~~
      //  25632    DW    9/22/11  * Initial release
      //----------------------------------------------------------------
     PCleanupUpsAddr   b                   export
     DCleanupUpsAddr   pi            50a
     D  sIn                          50a   const

      // Work Data Structure
     D sOut            s                   inz like(sIn)
      /free
       // Upper Case
         sOut = %xlate(lower: upper: sIn);

       // Remove Punctuation
         sOut = %xlate(''',-.~`"\/':'         ':sOut);

       // Remove Double Spaces
         dow %len(%trim(sOut)) <> %len(%trim(%scanrpl('  ':' ':sOut)));
           sOut = %scanrpl('  ':' ':sOut);
         enddo;

       // Return cleaned value
         return sOut;
      /end-free
     PCleanupUpsAddr   e