TL;DR
We crafted a USPS Web Tools OpenAPI 3.0 specification from USPS PDF docs, then used the spec to generate modern USPS Web Tools API documentation with Redoc and host them on Netlify. Many companies offer an interactive API explorer as part of their documentation; we thought a good solution was a USPS Web Tools public workspace with Postman. Finally, we created a video tutorial so you can try out these tools.
Let’s look at the challenges we faced improving the developer experience.
Who, What, Why?
At Lob, 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. 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 technology and the USPS Web Tools APIs reference docs 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. 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 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 is an open-source tool for generating documentation from OpenAPI (fka Swagger) definitions. There is a paid service with more features called Redocly, 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.
USPS public workspace with Postman
We have experience working with Postman public workspaces as Lob launched one 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.
Conclusion
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