Modernizing the USPS Developer Experience
Tags: devrel, usps, openapi
Published: 2022-04-29 10:20:00


## TL;DR

We crafted a [USPS Web Tools OpenAPI 3.0 specification](https://github.com/lob/usps-webtools-api) from USPS PDF docs, then used the spec to generate [modern USPS Web Tools API documentation with Redoc](https://www.uspsweb.tools) and host them on [Netlify](https://netlify.com/). Many companies offer an interactive API explorer as part of their documentation; we thought a good solution was a [USPS Web Tools public workspace](https://www.postman.com/lobteam/workspace/usps-web-tools-public-workspace/overview) with Postman. Finally, we created a [video tutorial](https://www.youtube.com/watch?v=6Vb5CSti4eA) so you can try out these tools.

Let’s look at the challenges we faced improving the developer experience.

## Who, What, Why?

At [Lob](https://www.lob.com), we help developers automate sending letters, checks, and postcards, and improve address quality through RESTful APIs. The mail that flows through Lob to our print partner network reaches its final destination with help from the U.S Postal Service. Lob also utilizes the USPS tracking data in our webhooks so customers can observe the journey of each mail piece. 

We appreciate how the U.S. Postal Service opens up their data and makes it easy to access with a free [USPS Web Tools® account](https://www.usps.com/business/web-tools-apis/web-tools-registration.htm). Their current API set includes address verification, rate calculators, shipping labels, package pickup, domestic mail service, tracking & confirmation, and even an API to retrieve Hold for Pickup facility information. Unfortunately, many of these endpoints were developed over a decade ago and during the intervening years developers have come to expect increasingly better and better developer experiences.

**As we looked at the USPS Web Tools site, we started thinking of ways to improve the developer experience.** Now, we can’t change the APIs themselves, but perhaps an open-source project that leverages new tools could make a difference. API documentation often ranks number one for how developers evaluate a technology and the [USPS Web Tools APIs reference docs](https://www.usps.com/business/web-tools-apis/documentation-updates.htm) are only available as PDFs, so we decided to start there.


## Reverse engineering an OpenAPI specification

Taking existing API docs and creating a OpenAPI specification from them might sound straight forward, but it can be tricky. APIs do not always follow established standards and quirks may have crept in that don’t fit a specification. We achieved our goal of a valid specification, but compromises were necessary to accommodate the U.S. Postal Service API design.

### Problem #1

Our first challenge was the non-standard authentication used in the USPS APIs. OpenAPI 3.0  defines the authentication approach in the [security scheme component](https://spec.openapis.org/oas/v3.1.0#security-scheme-object). Available types include http for basic and bearer, apiKey where a key is passed via a header, query param or cookie, oAuth 2 and OpenID connect. USPS APIs don't use any of these authentication types. Instead, a USERID attribute equal to the developers Web Tools username on the parent node of the XML query param acts as an API key. 
 
For example, `<AddressValidateRequest USERID="{WEB_TOOLS_USERNAME}">`

### Solution 

Omit the security scheme from our specification and use the Redoc option noAutoAuth=true. This removes an automatically inserted link to authentication details that accompanies each endpoint. We still wanted to explain how USPS Web Tools authentication works. To accomplish this we added a description of authentication using tags in OpenAPI and set the x-traitTag to true. Redoc inserts a [new section](https://www.uspsweb.tools/#tag/Web-Tools-Authentication) without an associated endpoint—voila!

### Problem #2

For an OpenAPI 3.0 specification to be valid each path must be unique and methods (GET, PUT, POST, DELETE, etc) can only be used once per path. This presents a problem since all endpoints use the same path `/ShippingAPI.dll `and define their function via the **API** query param.

### Solution

To create an OpenAPI specification that is valid (with all endpoints) and generates accurate documentation, we used this hacky work around of defining a parameter named API **AND** appending it to the path (thereby making each path unique).

```
/ShippingAPI.dll?API=Verify:
  get:
   summary: 'Verify a US address'
   operationId: verify
   tags:
    - Address
   parameters:
    - name: API
     in: query
     description: This query parameter defines the resource you are accessing
     required: true
     schema:
      type: string
      default: Verify
```

### Problem #3

The biggest challenge in this project was the size and complexity of response objects. USPS documentation does not provide examples of the variety of responses you might encounter based on different conditions. At times, it is hard to tell how children objects are organized and if they are returned as arrays. We’ve done our best to document these, when possible we’ve replicated conditions to return an example response and confirm the object structure.

### Solution

We hope USPS employees and the developer community can file issues or make pull requests to improve the OpenAPI specification and documentation over time.

## Building documentation with Redoc

[Redoc](https://github.com/Redocly/redoc) is an open-source tool for generating documentation from OpenAPI (fka Swagger) definitions. There is a paid service with more features called [Redocly](https://redocly.com/), but for this project we are utilizing the open source redoc-cli tool.

### Problem #4

Another challenge was how to include an example for the XML parameter. XML can be complex and examples are worth 1,000 words. In Redoc, parameters that are a simple type (string, integer, date) support examples, but object type examples don’t display.

### Solution

To work around this, we added examples in the description wrapped in a styled div with non-breaking whitespace to add proper indentation to the example. I know this information might have caused a spit-take, but you can’t deny [the results](https://www.uspsweb.tools/#tag/Address).

![usps_docsexample.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651075110415/IdB5BzvoW.png)

## USPS public workspace with Postman 

We have experience working with [Postman](https://www.postman.com/) public workspaces as Lob [launched one](https://www.postman.com/lobteam/workspace/lob-public-workspace/overview) last summer. A workspace is a group of collections and each collection can contain one or more requests. Currently, we have address validation, domestic mail service, and track & confirm collections. You can fork the collection and the environment in order to set your Web Tools username and start exploring APIs.

### Problem #5

The XML parameter is the one thing you’ll modify when exploring these APIs, but XML is complex and trying to edit it on a single line text input isn’t great.

### Solution

We used the pre-request script tab in Postman. We defined all the values as variables at the top of the script. Developers can easily modify the values and when a request is made the XML param value is set automatically by the script.

![usps_postman.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651075142145/BlxwtkzBk.png)

## Conclusion

Though challenging, we enjoyed working on this project and hope the result is that you can take advantage of the USPS APIs more easily. If you want to give it a try, we created a video tutorial: [How to use the USPS Web Tools API with Javascript and Node](https://www.youtube.com/watch?v=6Vb5CSti4eA). Learn how to connect to the USPS address verification APIs using standard Node packages Axios and XMLBuilder2. We walk through installing these libraries and the code needed to send XML and turn your XML response into JSON.

You may be required to use some creativity when leveling up a developer experience. You may argue with yourself from time to time between the “right” way and bending the rules in service of the developer. So, I’ll leave you with a quote.

> Better a diamond with a flaw than a pebble without. –Confucius