Author: Shane Smith May 23, 2018 5 Min READ

Give it a REST: The REST API to Optimize Your WMS

5 Min READ
Give it a REST: The REST API to Optimize Your WMS

Share

My name is Shane Smith and I am the Director of Implementation and Support. I have been with Extensiv for a couple of exciting and high-growth years. Prior, I worked mostly in the enterprise business to business (B2B) space with many years focused primarily on security and middleware. Before moving to the dark side (management), I had various software engineering and architect roles. With Extensiv’s REST API coming to life and the opportunity to “eat our own dogfood” to solve some internal challenges by dusting off the coding keyboard, the answer was “heck yeah.”

I’m not into holy wars, and my preferred coding language is Java since a lot of what I am going to share is from my nights and weekends, the weekend clause applies - I get to use what I want to use.

So, Java it is. This blog is about utilizing the Extensiv REST API via Java. If you want to program in something else, feel free to post anything you would like ;)

For our own Extensiv’s internal uses, we often need to move large amounts of varying and dependent warehouse data from one source to another. The scope, so far, has included customers, items, and inventory data. We’ll start with this objective, in the beginning, and share some examples of how you can build and re-use some Java code for your own purposes.

For starters, and to set the stage, here is what I used for various stages of development. My personal endorsement is that all these work and my weekend clause apply to all:

  • System Environment/IDE
    • I use Java 1.8, Eclipse Oxygen, and program on Macintosh
  • JSON Test Clients / Tools / Libraries
    • When needing to validate and/or format JSON, I used the free online web version of JSON Formatter, located here
    • I use CocoaRestClient (available here
      • Fiddler is another popular option, is also available on Macintosh, and is available here
    • I experimented with a couple JSON libraries, and ultimately settled on using the package: org.json.simple (json-simple) for most of the JSON
      • There are many implementations (weekend clause)
      • Simple-json’s home page is located here
      • Simple-json’s external .jar is located here for download
      • Mkyong.com has a tremendous amount of samples of using this library that is exceedingly easy to follow and leverage. I highly recommend his site. Check him out here
  • Extensiv’s REL and Web API documentation is located here
    • Not your typical does not apply disclaimer: consider this documentation beta from a developer’s standpoint. Also, note that these pages, as is the REST platform in general, are continuously changing (because they really are)

There are a number of REST API calls you are likely going to want to reuse. Because the scope of my project was in flux, I chose to create a static utility class to simplify and speed up development. I could always choose to come back and refactor the code if it made sense. Sound familiar?

For me, I like ease. So, the first thing is writing a couple of utility methods that I can refer to easily is always a good place to start.

Step 1: In accordance with Extensiv’s documentation, one is provided with a ClientId and a ClientSecret string to use in order to get a temporary access token to make further API calls. These strings must be concatenated with a colon (“:”), and then encoded. We’ve come a long way since Java 1.1 and this is pretty easy. Here is a simple method, from my utility class, that returns the Base 64 UTF-8 encoded authorization string that is used to return a current access token for REST access to Extensiv:

import java.util.Base64;

public static String getAuthorizationString(String inClientId, String inSecretKey) {
    String encodeMe = inClientId + ":" + inSecretKey;
    String encoded = Base64.getEncoder().withoutPadding().encodeToString(encodeMe.getBytes());

return encoded;
}

Step 2: We need to build the JSON payload (the information and details we are sending) in order to get a proper access token. We’ll absolutely get into utilizing the proper JSON library and doing this “right”, but for the sake of getting an example up and going quick, let’s go full-on cheat-mode and go quick and dirty so we can get something working quick - it’s a super simple and static payload at this point after all. Here’s a simple static method that builds the JSON goodness for us that is based on our 3PL GUI ID.

This method does the trick:

public static String getAccessTokenJSON(String inThreePLGuiId, String inUserLogin) {
    String returner = "";
    returner = "{\n" +
                 "\"grant_type\": \"client_credentials\",\n" +
                 "\"tpl\": \"" + inThreePLGuiId + "\",\n" +
                 "\"user_login_id\": \""+ inUserLogin"+\"\n" + "}";
    return returner;
}

IMPORTANT NOTE: Make sure to reference http://api.3plcentral.com/rels/auth for understanding and making the appropriate changes to the payload as it fits your specific needs – along with understanding the possible errors!

Step 3: Now, we are at the point where we can get our temporary access token that we use to make other REST API calls. Here is an example of another utility method that is used to get a temporary access token using our authorization, URL (secure-wms.com/AuthServer/api/Token), and our REST payload from Step 2:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;

import java.net.HttpURLConnection;
import java.net.URL;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

public static String getAccessToken(String inUrl, String inAuthorizationToken,
                                                          String inThreePLGuiId, String inUserLogin) {

String replyMessage = "";
String returner = "";
try {

// CREATE THE URL CONNECTION
URL getAccessTokenUrl = new URL(inUrl);
HttpURLConnection conn = (HttpURLConnection) getAccessTokenUrl.openConnection();

// ESTABLISH THE URL CONNECTION AND PROPERTIES.
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Host", "secure-wms.com");
conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("User-Agent", "Fiddler");
conn.setRequestProperty("Authorization", "Basic " + inAuthorizationToken);
conn.setRequestProperty("Accept-Encoding", "gzip,deflate,sdch");
conn.setRequestProperty("Accept-Language", "en-US,en;q=0.8");
conn.setRequestProperty("Content-Length", "113");

// WRITE THE REQUEST TO THE HTTP CONNECTION
OutputStream os = conn.getOutputStream();
os.write(getAccessTokenJSON(inThreePLGuiId,inUserLogin).getBytes());
os.flush();

// READ THE REPLY STRING FROM THE SERVER
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));

String output;
while((output = br.readLine()) != null) {
replyMessage += output + "\n";
}

// ***NOTE*** WE SHOULD CHECK FOR A SUCCESSFUL RETURN HERE AND ONLY
// CONDITIONALLY CONTINUE!!!

// CLOSE DOWN THE HTTP CONNECTION
conn.disconnect();

// USE THE JSONPARSER TO CREATE THE JSON OBJECTS TO
// RETRIEVE THE ACCESS CODE FROM
JSONParser parser = new JSONParser();
Object obj = parser.parse(new StringReader(replyMessage));

// GET THE ACCESS_TOKEN AND GET READY FOR RETURN
JSONObject jsonObject = (JSONObject) obj;
returner = (String) jsonObject.get("access_token");    

}
catch(Exception e) {
        e.printStackTrace();
}

// SINCE I WAS NAUGHTY AND DIDN’T CHECK THE RESPONSE, I OPTIMISTICALLY, RETURN
// THE ACCESS TOKEN AS A STRING
return returner;
}

Sample usage of this code may looking like this:

String authorization = getAuthorizationString(“MyClientId”, “MySecretKey”);
String accessToken = getAccessToken(“http://secure-wms.com/AuthServer/api/Token”, // TOKEN URL
                                                                authorization,                                                     // AUTH STRING
                                                               “{aba0000a-000a-00a0-a000-00000000abc0}”, // TPL GUID
                                                               “1”);                                                                    // USER ID

System.out.println(“Access token = “ + accessToken);

So, this little bit of code is mighty powerful. We have created a method that encodes the authorization for us. Also, we have a single method that returns an access token to use later on in our application.

For my code, I made a lot of these variables customizable in a “preferences” dialog and stored them in a property file so they would be automatically passed to me. I STRONGLY SUGGEST also storing the access token for reuse somewhere to help both the application’s performance and to lessen the number of API calls.

An access token is good for an indeterminate amount of time, but the rule of thumb is about an hour. There are three ways of handling this in the code:

  1. Fetch a new access token when a REST call fails for authorization credentials
  2. Fetch a new access token after a determinate amount of time from the last fetch
  3. Fetch a new access token after a preset number of usages

For me, again, quick and dirty, I’m heavily utilizing the API to move a large amount of data, so from a rapid development standpoint, I used the least desirable and easiest, number 3. Getting a new token after 500-1000 calls worked out to be a small percentage and easily fit in the time boundaries for me.

It has to be said, that the unlisted option above, fetching a token for every single call is completely out of the question. This would be a perfect way to double your program’s execution time (or worse) and also unnecessarily load the host server with useless and unnecessary requests. These is “things that shouldn’t have to be said”, but coding something in this manner is equivalent to crawling a server and a good way to get your client access flagged, throttled, or even worse, banned. Don’t create and become a problem, don’t do it. #wordsofwisdom

Next, we will start building on these three methods, get in and use the JSON library, and start scratching the tip of the iceberg of all that one can do (an awful lot) with our REST API.

Obvious enhancements to work on and get familiar with are changing the payload from String to JSONObject in getAccessTokenJSON and refactoring its usage in the code. Reference Mkyong.com and the link listed above for great and straightforward examples of doing this and make sure you conform to JSON listed at Extensiv REL documentation.

Another enhancement, is our getAccessToken method itself should check the connection’s response and handle a failed response accordingly by using the connection’s getResponse() method. Feel free to take a stab at tidying up that code as well.

 

Written By:
Shane Smith

Director of Implementation & Support Shane brings 20+ years of Customer Success and Software Engineering experience to 3PL Central from enterprise B2B Security, GovCon and Middleware industries. Before shifting his career to focus on customer’s success, Shane held numerous software developer and architect roles and was also an ICBM targeting and weather satellite programmer in the United States Air Force at Offutt AFB in Omaha, Nebraska.

Topics:

Latest Insights

Apr 18, 2024 8 Min READ