3.6. RESTful URIs, API Calls, and JSON

In considering how to treat a collection of SOA servers as a fabric for programming, we’ve addressed rows 1–3 of Figure 3.5. We next describe how data is passed to or received from such services, and some operational considerations such as authorization (is the client allowed to make this API call on this resource?) and how errors are handled.

At the highest level, there are three ways to pass parameters from an HTTP client to a service: in the URI, in the request body (for POST or PUT requests), and rarely, as the value of an HTTP header.

When the number of parameters is small, and in particular when the parameters are sim- ple types such as strings or numbers, they can often be passed as parameters embedded in the URI, as Figure 3.2 showed: param1=value1&param2=value2&...&paramN=valueN. This situation is typical for GET requests, where we’re usually asking for data based on an ID and perhaps some optional parameters. For example, verify using the TMDb API documentation that the route GET /search/movies?query=Batman+Returns will search TMDb for a movie whose title matches the query string “Batman Returns”.

When the data to be passed is more complex, or when the API operation involves a state-changing HTTP method such as POST or PUT, the data is sent as part of the request body, as browsers do when submitting the values entered on a fill-in form. (Recall that GET requests have no request body.) How is this data presented to the server? While there are many choices, there is no question that the SOA community has rapidly converged on JSON (pronounced “JAY-sahn”), or JavaScript Object Notation, as the common interchange for- mat. JSON is so called because its syntax resembles, but is not identical to, the syntax of a JavaScript object literal—a set of unordered key/value pairs, like a Ruby hash, Python dict, or Java HashMap) of key/value pairs. In JSON, each key (or “slot,” as we’ll learn in Chapter 6) must be a double-quoted string, and its value may be a simple type (string, numeric, true, false, null), another object, or a linear array each of whose elements can be any of these, including another array. The JSON web site shows some simple examples, and because of JSON’s popularity as the default data format for SOA, virtually every modern language comes with libraries to both generate and parse JSON. Blank space (spaces, tabs, newlines) is optional in JSON, and most servers return blankspace-free JSON. Unix command-line tools such as json_pp and browser extensions like JSONView restore spacing and indentation to make JSON more readable. Note that calls that require sending JSON data may also allow (or require) sending some parameter values encoded in the URI; you must check the API documentation for details.

# set endpoint for TMDb API
export BASE=https://api.themoviedb.org/v3
# set our API key for use in other calls
export KEY="my API key here"
# Search for a movie by keywords
curl "$BASE/search/movie?api_key=$KEY&query=Batman+Returns"
# For better legibility, pipe the output to json_pp:
curl "$BASE/search/movie?api_key=$KEY&query=Batman+Returns" | json_pp
# Start a new guest session
curl "$BASE/authentication/guest_session/new" | json_pp
# capture the guest session ID from Curl's output:
export SESSION=e91f07cca8166b7b1e707d8a826e8a38
# Create a file containing  the JSON object for rating a movie:
echo '{ "rating": 6.5 }'  > myrating.json
# Use Curl to POST a movie rating request using the file's contents:
curl -X POST -H "Content-Type: application/json" -d @myrating.json \
"$BASE/movie/364/rating?api_key=$KEY&guest_session_id=$SESSION"
Figure 3.7: Try the lines of this shell script one at a time, replacing the value of KEY with your TMDb API key. After line 8 you’ll have to visually parse out the correct movie ID from the JSON response, and after line 10 the correct guest session ID to use in line 12. If your system doesn’t have json_pp installed, you can omit it.

HTTP headers are sometimes used to pass very specialized types of parameters. For example, some APIs require you to add the HTTP header Content-Type: application/json to a request that will be accompanied by a JSON payload, while others don’t. Finally, nearly all APIs require authorization—the client must prove it has the right to make each API call. While authorization schemes vary, the mostcommonistoincludeaclient-specificAPIkeywitheachrequest. APIkeysareusually requested manually and may be free or paid (TMDb’s are free), and the service may impose limits such as the number of calls made per day. Depending on the API, the key may be sent as an argument in the URI (as with TMDb), as the value of an HTTP Authorization: header, or either.

Putting this all together, Figure 3.7 shows the use of the curl tool to do a sequence of RESTful API requests—all but the last are :code:`GET`s—exercising the TMDb API. Note in particular that the API key is a required URI parameter for every request, and verify against the API documentation the correct format for the object in line 14 representing the desired rating you wish to submit for a movie.

What if an error occurs? Recall from Section 3.2 that every HTTP response begins with a 3-digit status code; these are cataloged and maintained7 by the World Wide Web Consortium. Services use status codes to indicate various types of errors:

  • 2xx codes indicate success. For example, code 200 (“OK”) would be the usual success status for a GET, whereas code 201 (“Created”) would be more typical for a POST that creates a new resource.

  • 3xx codes indicate the client must take further action to complete the request—that is, a redirect. Perhaps the requested resource has moved to a different URI, which would be specified in the response body.

  • 4xx codes indicate that the service encountered an application error processing the request. 400 means the request was malformed, but other codes for well-formed requests include 401 (Unauthorized), 402 (Payment required), and others.

  • 5xx codes indicate a problem with the service infrastructure itself—an error that prevented the remote call from even completing, such as the server encountering an internal error so severe that it is too broken to even explain what went wrong.

In case of an error (any status other than 2xx), the response body usually contains a message explaining what went wrong. Depending on the API, the response body may consist simply of this string, or it may be a JSON object with a single string-valued slot named message or error or something similar.

Self-Check 3.6.1. You try an API call on TMDb and the status code of the response is 400. Assuming TMDb adheres to the official W3C semantics of the status codes, which of the following could be the reason for the error: (a) your request was malformed so could not be attempted; (b) you forgot to include your API key; (c) your request and API key were well-formed, but you are attempting an operation that you’re not authorized to do.

(a) is most likely. 401 Unauthorized would be more likely for the other two cases.