The Anatomy of an HTTP Request

An API, or Application Programming Interface, is what allows one software application (such as your own) to interact with another (such as ShipEngine).

APIs can be an important part of streamlining your business processes and integrating with vendors who provide the services your business needs. But, at ShipEngine, we recognize that integrating an API may be a brand-new to some of our users.

And that’s perfectly fine. In fact, integrating with an API is a new concept to most of our users. For those of you who may not be familiar with API integrations, I’ll use this post to discuss the parts of what’s called an “HTTP request” — and how an HTTP request can be used to make an API call.

HTTP: The Protocol for Sending and Receiving Data

HTTP (HyperText Transfer Protocol) is the protocol used to send and receive virtually all data on the Internet. When you make an API call, an HTTP client sends a request to an HTTP server, which then sends back to the client a response containing the requested data or “resource” as it is normally referred to.

The ShipEngine API uses an extension to the HTTP protocol known as HyperText Transfer Protocol Secure (HTTPS). With HTTPS, the data sent between the client and server is encrypted using an SSL certificate. This means that data intercepted by a third party cannot be read.

For simplicity’s sake, I will refer to the protocol simply as HTTP throughout this post. But you can always rest assured that we will always protect your data at ShipEngine.

URLs: How You Access Resources

The ShipEngine API allows you to create and retrieve several resources, including carriers, shipments and labels. Each resource is accessible by a URL, with each of the URLs listed in the ShipEngine documentation being relative to the host name.  

For example, our documentation indicates the URL ‘/v1/labels’ is used for interacting with label resources. This URL is relative to the base URL ‘https://api.shipengine.com’, making the full URL to interact with label resources ‘https://api.shipengine.com/v1/labels’. This is the first piece of an HTTP request — the URL to the resource.

HTTP Methods

As noted in the introduction, you interact with an API to get data from a system and to create or update data in a system. HTTP requires different verb-named methods depending on the nature of your request. Here’s a look at the description of each HTTP method as shared in the ShipEngine documentation:

GET — Used for retrieving resources.

POST — Used for creating resources.

PUT — Used for updating or replacing resources.

DELETE — Used for deleting resources.

PATCH — Used for posting partial resources, such as adding funds to insurance using the ShipEngine API.

In order to list all the labels that have been generated for an account, you would use the GET HTTP method. The full HTTP request would consist of a verb, or method, and a URL to the resource. So, to get a list of labels, the full request would be ‘GET https://api.shipengine.com/v1/labels’.

HTTP Headers: Identifying Authorized Users

For an HTTP server to respond to a request from an HTTP client, it must first validate that the request is coming from an authorized user. This information is transferred with the request via HTTP headers. HTTP headers are used in both HTTP requests and HTTP responses to provide information about the request or response or to provide information about the data object sent in the message body.

When using the ShipEngine API, you pass your API key, which can be obtained (free and with no credit card required) from the ShipEngine dashboard, in a header named ‘api-key’. We’re planning a future post that describes how to make an HTTP request using Javascript and NodeJS. This future post will show specifically how to set these headers in your code. But, for this post, you only need to understand how headers are used to include data about a request or response. In addition to authenticating yourself by using an ‘api-key’ header, you should also include a ‘Content-type’ header set to ‘application/JSON’. This indicates that you are sending JSON (short for JavaScript Object Notation) or expect to receive JSON in the message body.

Once the response is sent, the server closes the connection to the client and does not maintain any connection information. This is known as a “stateless protocol,” and it means that the client must identify itself every time it makes an HTTP request to the server. Therefore, the HTTP headers above must be sent with every API request to the server.

Using JSON Payloads

As mentioned above, we include a header indicating that the content type we are sending or expect to receive is JSON — the standard format for sending data in an HTTP request or response using a REST API. REST stands for Representational State Transfer and is the modern architectural style used for creating APIs. A JSON object consists of a set of key-value pairs that can be nested inside one another. This is an example of a JSON object or “payload” for creating a label using the ShipEngine API:

{
  "label_id": "se-202887313",
  "status": "completed",
  "shipment_id": "se-202887313",
  "ship_date": "2019-04-01T05:00:00.000Z",
  "created_at": "2019-04-01T13:53:46.508Z",
  "shipment_cost": {
	"currency": "USD",
	"amount": 6.86
  },
  "insurance_cost": {
	"currency": "USD",
	"amount": 0.0
  },
  "tracking_number": "9405511899560441854156",
  "is_return_label": false,
  "is_international": false,
  "batch_id": "",
  "carrier_id": "se-123890",
  "service_code": "usps_priority_mail",
  "package_code": "package",
  "voided": false,
  "label_format": "pdf",
  "label_layout": "4x6",
  "trackable": false,
  "carrier_code": "stamps_com",
  "tracking_status": "unknown",
  "label_download": {
	"href": "https://api.shipengine.com/v1/downloads/aFbxNUVCZ0SDHHp-BmcKjA/testlabel-202887313.pdf"
  },
  "form_download": null,
  "insurance_claim": null,
  "packages": [
	{
  	"package_code": "package",
  	"weight": {
    	"value": 1.00,
    	"unit": "ounce"
  	},
  	"dimensions": {
    	"unit": "inch",
    	"length": 0.0,
    	"width": 0.0,
    	"height": 0.0
  	},
  	"insured_value": {
    	"currency": "usd",
    	"amount": 0.00
  	},
  	"tracking_number": null,
  	"label_messages": {
    	"reference1": null,
    	"reference2": null,
    	"reference3": null
  	}
	}
  ]
}

You can see that ‘label_id’ is a single key-value pair while ‘shipment_cost’ is a key whose value contains another JSON object consisting of the keys ‘currency’ and ‘amount’. The key ‘packages’, on the other hand, contains an array (or collection) of keys whose values consist of multiple key-value pairs. The ShipEngine documentation contains plenty of examples of the JSON you will need to construct to make different calls using the ShipEngine API. The response you receive from the HTTP server will also include a data object in this format.

Putting it All Together

To put it all together, here’s a breakdown of all the components in a full HTTP request. The examples in the ShipEngine documentation use a tool called Curl to execute HTTP requests, and so “curl” is the first word that appears in a full request. After the keyword ‘curl’, we have the URL for the labels resource. The ‘-X’ after the URL indicates that we are passing a custom HTTP request method to be used instead of the default GET. In this example, we are using a POST method because we wish to create a new label using the data in the message payload.

The ‘-H’ indicates an HTTP header and the ‘-d’ indicates the data or payload we wish to send, which is in JSON format. The back slashes at the end of the lines simply indicate that the command continues on the next line.

curl https://api.shipengine.com/v1/labels -X POST \
  -H "Content-type: application/json" \
  -H "api-key: ElJkhJuQIRoFq/kDEblco4LpZqRCdYNIoAVG7SywSXw" \
  -d '
{
  "shipment": {
	"service_code": "usps_priority_mail",
	"ship_to": {
  	"name": "Mickey and Minnie Mouse",
  	"phone": "+1 (714) 781-4565",
  	"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": "512-485-4282",
  	"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"
    	}
  	}
	]
  },
  "test_label": true,
  "is_return_label": false
}

The HTTP server will respond to the API request with the following:

{
	"label_id": "se-test-3719474",
	"status": "processing",
	"shipment_id": "se-3719474",
	"ship_date": "2019-04-01T00:00:00Z",
	"created_at": "2019-04-01T21:09:50.9433704Z",
	"shipment_cost": {
    	"currency": "usd",
    	"amount": 0
	},
	"insurance_cost": {
    	"currency": "usd",
    	"amount": 0
	},
	"tracking_number": "9999999999999",
	"is_return_label": false,
	"rma_number": null,
	"is_international": false,
	"batch_id": "",
	"carrier_id": "se-16161",
	"service_code": "usps_priority_mail",
	"package_code": "package",
	"voided": false,
	"voided_at": null,
	"label_format": "pdf",
	"label_layout": "4x6",
	"trackable": true,
	"carrier_code": "stamps_com",
	"tracking_status": "unknown",
	"label_download": {
    	"href": "https://api.shipengine.com/v1/downloads/0/E-rPHU39k0yQDXpRRGwTig/testlabel-3719474.pdf"
	},
	"form_download": null,
	"insurance_claim": null,
	"packages": [
    	{
        	"package_code": "package",
        	"weight": {
            	"value": 1,
            	"unit": "ounce"
        	},
        	"dimensions": {
            	"unit": "inch",
            	"length": 0,
            	"width": 0,
            	"height": 0
        	},
        	"insured_value": {
            	"currency": "usd",
            	"amount": 0
        	},
        	"tracking_number": null,
        	"label_messages": {
            	"reference1": null,
            	"reference2": null,
            	"reference3": null
        	}
    	}
	]
}

Summary

That’s all there is to it! The information contained in this post should help you better understand the ShipEngine documentation and prepare you for my next post — the one that will share how to make an API request by writing Javascript and NodeJS.

You’ll likely have question, though, and we’re always here to provide answers. You can visit our Help Center to find a wealth of resources about integrating and using the ShipEngine API, and users at any plan level can contact support via email, chat or Slack.

Leave a Reply

Your email address will not be published. Required fields are marked *