APIs are often the undercurrent that powers successful business processes. By integrating with the right vendors providing the right services, your business can free up time and resources that can be reallocated to other pressing tasks. Modern companies use APIs to build email lists, to create maps, to store and manage data and much more.
In a previous post, I outlined the anatomy of an HTTP request and how to use an HTTP request to make an API call. As a follow-up, I’ll use this post to dig deeper and demonstrate how to construct an HTTP request using Node.js.
Getting to Know JavaScript
JavaScript is the most commonly used client-side scripting language. If you’re developing a web-based application, you may already be embedding JavaScript directly inside your HTML pages.
Web browsers include a built-in JavaScript interpreter and a set of standard libraries for working with web pages that allow JavaScript to run directly inside your web application.
Getting to Know Node.js
If you wish to run your JavaScript programs outside a web browser, you need Node.js.
Node.js (commonly referred to simply as ‘Node’) bundles the V8 JavaScript interpreter that runs inside Google Chrome along with libraries that allow you to perform file system I/O and networking. This allows you to use JavaScript to write applications that run outside a web browser.
One More Tool to Know: Axios
There’s a handy tool that simplifies making HTTP requests in Node. Meet Axios, a Javascript library that handles much of the complexity of HTTP requests. The rest of this post assumes you are somewhat familiar with Javascript and Node — but no worries if you aren’t! You can create a functioning Node development environment by following the instructions in this post. Once you have a functioning Node environment, you can install Axios using npm or yarn.
How to Get Started
The example below will focus on using Axios to make an HTTP request in a standalone script using Node. That said, you can also embed Axios HTTP requests directly alongside your HTML and CSS content in your web pages, but that is outside the scope of this post.
The first thing the script does is create a variable to use as a reference to the Axios library, which gives it access to all the Axios methods. The script looks like this:
const axios = require('axios');
Next, the script creates and sets the ‘headers’ variable and assigns the HTTP headers to use when making HTTP requests using Axios. Included is the API key, which can be obtained (free and with no credit card required) from the ShipEngine dashboard.
const headers = { 'api-key': '<your-api-key>', 'Content-Type': 'application/json', };
The ‘headers’ variable is then used in the ‘config’ variable to specify the HTTP headers we wish to use along with the base URL and a function called ‘validateStatus’ that prevents axios for throwing errors for HTTP status codes outside of the normal successful range . If the JSON element name is the same as the variable name to which we want to set it, the preferred convention is to list the name once. For example, ‘headers’ instead of ‘headers: headers’ — like this:
const config = { headers, baseUrl: 'https://api.shipengine.com', validateStatus(){ return true; } };
Using Async Functions
HTTP requests are handled asynchronously in JavaScript, which means that a program can move on to something else without waiting for the request to complete. This is convenient when performing a long-running operation, but there are times when you need one operation to complete before performing the next. Also, there are times when you need to wait for the output of one operation to use as the input to the next operation. For example, if you make a ShipEngine API call to create a shipping label, you must wait for that task to complete so that you can retrieve the ‘label_id’ to use in the subsequent API call to track the label.
JavaScript has always allowed you to wait for an asynchronous operation to complete before moving to the next one, but the specific way that JavaScript allows for waiting has evolved over time. The various approaches used to wait for completion of an asynchronous operation (including callbacks, promises and async/await) are outside the scope of this post. If you’re interested in reading more on this subject, here’s a great explainer.
The example script below uses the ‘async/await’ approach, which is why you see the async function wrapping the API call. This structure uses the ‘await’ keyword to indicate that the program should wait for the asynchronous API call to complete before moving on the next action. This async function wraps the call to create a label.
async function createLabel(data) { let response = await axios.post('https://api.shipengine.com/v1/labels', data, config); return response; }
This function accepts a JSON object containing the data required to create a UPS label. It uses the ‘axios’ variable and the ‘post’ method and passes the same three things:
- The URL for the endpoint to hit
- The JSON object containing the label data
- The Axios config
This function uses the ‘await’ keyword so that the function does not return until the API call to create the label is complete.
The script then creates a function to obtain the tracking information for the label that was just created.
async function trackLabel(labelId) { let response = await axios.get('https://api.shipengine.com/v1/labels/${labelId}/track', config); return response; }
This method accepts the ‘label_id’ for the label we wish to track. As with the previous method, it uses the ‘axios’ variable but with one key exception: this function uses the HTTP ‘get’ method rather than the HTTP ‘post’ method. The HTTP ‘get’ method does not require a JSON object, so we only need the URL of the endpoint and the Axios config. Once again it uses the ‘await’ keyword to force the program to wait for the HTTP request to complete before executing the next line of code.
The script has now defined two independent asynchronous functions, ‘createLabel()’ and ‘trackLabel’.
The Next Step: Defining JSON Payloads
Before calling the function to create a label, the script creates a variable and assigns it a JSON object that defines the label it should create. See ShipEngine’s documentation for examples of the JSON required for each of the API methods that uses the HTTP Post method.
const labelData = { "shipment": { "service_code": "ups_ground", "ship_to": { "name": "Mickey and Minnie Mouse", "phone": "7147814565", "company_name": "The Walt Disney Company", "address_line1": "500 South Buena Vista Street", "city_locality": "Burbank", "state_province": "CA", "postal_code": "91521", "country_code": "US", "address_residential_indicator": "No" }, "ship_from": { "name": "Shippy", "phone": "5124854282", "company_name": "ShipEngine", "address_line1": "3800 N. Lamar Blvd.", "address_line2": "Suite 220", "city_locality": "Austin", "state_province": "TX", "postal_code": "78756", "country_code": "US", "address_residential_indicator": "No" }, "packages": [ { "weight": { "value": 1.0, "unit": "ounce" } } ] }, "is_return_label": false };
Putting it All Together
Now that we’ve defined a function to create a label and a function to track the label, we are ready to put it all together. The function ‘createAndTrackLabel()’ is where the business logic is implemented. Inside this function, we call the ‘createLabel()’ function with the ‘await’ keyword so that program execution waits until the ‘createLabel()’ call completes. Finally, the ‘createAndTrackLabel()’ function obtains the tracking status from the ‘trackLabel’ response, passes it to the ‘trackLabel’ method, obtains the status from the response and prints a simple status message to the screen.
async function createAndTrackLabel(data){ let response = await createLabel(data); let labelId = response.data.label_id; let trackingResponse = await trackLabel(labelId); console.log(`Label with label_id=${labelId} is in the $ state.`); };
Just to recap the code above, we begin by calling the ‘createLabel()’ function, passing the ‘labelData’ variable we created earlier. The next call tracks the label, but we don’t want to do that until label creation is complete, hence the use of ‘await’.
Next, we call the ‘trackLabel()’ function, passing the ‘labelId’ we obtained from the ‘createLabel()’ response.
The last step is to add a call to the ‘createAndTrackLabel()’ function so that the program knows where to start execution.
Let Us Know How We Can Help
You can find the full script here. If you wish to run it, be sure to substitute a valid API key and use valid data in the JSON object. You’ll need to login to the ShipEngine user interface and connect a UPS carrier before this script will run to completion.
While this example does not provide fully functional error handling, it is a good starting point for understanding how to use Node to call the ShipEngine API.
And, if you get stuck, you can count on us any time. We’re here to provide support and guidance as you get up and running with ShipEngine. Just reach out to talk to a shipping expert.
Leave a Reply