Using Postman, Swagger and the RingCentral API

John Wang
RingCentral Developers
5 min readApr 24, 2017

Postman is a popular tool for developing against APIs and our team at RingCentral and our customers use it for the RingCentral REST API. We already use Swagger UI to power our API Explorer which is very useful but sometimes you just feel like a Postman.

This article is about building the RingCentral Postman Collection using Swaggman, a new Swagger to Postman collection converter I wrote in Go. To use the Postman collection, simply import the collection into Postman which is covered in the Getting Started with RingCentral and Postman YouTube video. The specification uses the OAuth 2.0 Password Grant (aka Resource Owner Password Credentials Grant — ROPC) so your RingCentral app will need to have that enabled.

Background

I’m a big Swagger UI and example code fan so while I saw my teammates use Postman, I continued to building custom code examples using SDKs. However, after seeing partial Postman collections created by hand and receiving some customer requests, I wanted to automate the process of building a Postman collection to accomplish the following:

  • Create a complete Postman collection of all our 70+ public API endpoints
  • Reduce the effort to create and maintain the RingCentral Postman collection
  • Improve the quality and correctness of the RingCentral Postman collection

We use the Swagger 2.0 / Open API Initiative (OAI) 2.0 spec to specify our APIs for our API Explorer and for auto-generation of our SDK classes, so it was natural to leverage all the work and QA done to create that specification.

Why a New Swagger to Postman Converter?

There are already a number of Swagger to Postman converters available including one built directly into Postman so why a new one?

  • Postman’s built-in Swagger 2.0 importer has some limitations discussed on Github issue #843.
  • Other importers import Swagger only and do not support overriding Swagger properties and adding custom Postman properties. Specifically, we wanted to use an environment variable for the API server hostname and load Postman request and response scripts.
  • I like doing data conversion using Go and existing open source solutions I found were in JavaScript, PHP and Scala. For data conversion I have a strong preference for static typing for correctness and thought a JVM was heavy for this use case.

The code shown below is included in the example convert.go code:

Overriding Swagger Properties

The RingCentral API uses two different hosts for our Production and Sandbox environments. For the API Explorer, we can programmatically set this in our customized Swagger UI, however, for Postman, I wanted a simple solution using environment variables. To do this, the converter takes a hostname which overrides the Swagger spec’s “host” property. This way we can see the following:

  • Production host: platform.ringcentral.com
  • Sandbox host: platform.devtest.ringcentral.com
  • Swagger 2.0 Spec (default): platform.devtest.ringcentral.com
  • Postman 2.0 Collection: {{RC_SERVER_HOSTNAME}}

We do this by creating a configuration:

cfg := swaggman.Configuration{
PostmanURLHostname: "{{RC_SERVER_HOSTNAME}}"}

Adding Scripts

To support RingCentral’s OAuth 2.0 Password Grant, we want to preset the Auth API calls with a request and response script to load and set environment variables. To do this, I created a minimal Postman Collection with auth that would be merged in with the converted Swagger spec. This is done by calling “MergeConvert” instead of “Convert”:

conv := swaggman.NewConverter(cfg)err := conv.MergeConvert(
swagSpecFilepath, pmanBaseFilepath, pmanSpecFilepath)

For the request, we add some JavaScript to set the Basic Auth header value from the app key and app secret environment variables. This is loaded in the script.exec for the “listen”: “prerequest” hook.

var appKey = environment["RC_APP_KEY"];
var appSecret = environment["RC_APP_SECRET"];
var apiKey = encodeBasicAuthHeader(appKey, appSecret);
postman.setEnvironmentVariable("basic_auth_header", "Basic ".concat(apiKey));function encodeBasicAuthHeader(appKey, appSecret) {
var apiKey = appKey + ":" + appSecret;
return btoa(apiKey);
}

For the response, we want extract the access token and load it as an environment variable for the “listen”: “test” hook.

var jsonData = JSON.parse(responseBody);tests["Contains an access_token"] = jsonData.hasOwnProperty('access_token');tests["Status code is 200"] = responseCode.code === 200;postman.setEnvironmentVariable("my_access_token"
, jsonData.access_token);

You can see these in this example base Postman Collection:

Adding Headers

For OAuth, we want to add the access token which we store in a Postman environment variable.

cfg := swaggman.Configuration{
PostmanURLHostname: "{{RC_SERVER_HOSTNAME}}",
PostmanHeaders: []postman2.Header{postman2.Header{
Key: "Authorization",
Value: "Bearer {{my_access_token}}"}}}

Notes

The following notes are discuss issues encountered during the development.

JSON Polymorphism and Go

The Swagger Spec 2.0 and Postman Collection 2.0 use polymorphism which was encountered for default values in the former and as part of the the “request.URL” property in the latter.

Default values are polymorphic in both Swagger and Postman. These are handled by the Go “interface{}” type and transparently moved from one spec to the other.

The Postman “request.URL” property can be a string or an object.

A URL string looks like following:

"url": "https://{{RC_SERVER_HOSTNAME}}/restapi/oauth/token"

A URL object looks like the following:

"url": {
"raw": "https://{{RC_SERVER_HOSTNAME}}/restapi/v1.0/account/:accountId/extension/:extensionId/message-store",
"protocol": "https",
"auth": null,
"host": [ "{{RC_SERVER_HOSTNAME}}" ],
"path": [
"restapi",
"v1.0",
"account",
":accountId",
"extension",
":extensionId",
"message-store"
],
"variable": [
{ "value": "~", "id": "accountId" },
{ "value": "~", "id": "extensionId" }
]
}

Swaggman always outputs a URL object to support path variables which have it’s own “variables” property in the URL object. In the following example, the Swagger URL parameters are converted to Postman variables with the correct Swagger defaults.

To read a Swagger spec with a these values, the current code attempts to unmarshal both using the encoding/json library. This would get expensive if a lot of polymorphism is used so I’m going to be thinking about how to better handle this, including deeper use of the interface{} type.

Postman vs. Swagger UI

Originally, a big advantage of using Postman was that you had to paste in your app key and app secret into our API Explorer, however, that has been enhanced to automatically let you select your app key and app secret. Currently, there are still a few differences.

OAuth Grant Type and Caching

  • The Postman Collection takes all values as environment variables and uses the Password Grant which allows you to set your credentials once.
  • The Swagger UI based API Explorer uses the Authorization Code Grant which still requires you to enter your username/password in the OAuth window.

JSON Request Bodies

  • Postman does not formally support JSON request bodies and they must be typed into a raw body field. The Postman Collection does not yet have example bodies, but we will look to add these.
  • Swagger supports JSON request bodies so you can easily type in the values you need.

Converting Other Swagger Specs

I haven’t tried this on other Swagger specs and this is still in development. However, I am interested in API specifications in general due to my interested in auto-generation of SDKs. You can find some Swagger specs of interested here:

If there’s anything you would like this to support, just post here or on the Github repo!

Thanks!

Much thanks to Benjamin Dean, who worked on and evangelized our initial Postman efforts including the scripts shown above and name of the project, as well as Julio Toledo who provided the customer inspiration to get this project out!

--

--

John Wang
RingCentral Developers

AVP Platform Products for @RingCentral with a focus on improving life through innovative products and software