OCLC Web Services: Error Handling

 

This is the third post in our series on the design of web services at OCLC. In our first two posts in the series, we discussed the overall strategy at a very broad level and URL pattern design. In this post, we provide an overview of error handling for OCLC Web Services, and then offer specific examples from the WorldCat Metadata API.

Overview of Error Handling

Error handling for OCLC Web Services involves inspecting the HTTP Response Code and retrieving error elements from the body.

HTTP Response Codes

OCLC adheres to the Hypertext Transfer Protocol when handling request errors.

Table 1 - List of HTTP Response Types

Category Description
1xx: Informational Communicates transfer protocol-level information.
2xx: Success Indicates that the client's request was accepted successfully.
3xx: Redirection Indicates that the client must take some additional action in order to complete their request.
4xx: Client Error Indicates the error lies with the client's request.
5xx: Server Error The server takes responsibility for these error status codes.



Our Design of OCLC Services documentation offers a specific list of HTTP Response Codes.

HTTP Response Formats

In addition to interpreting the HTTP response codes, the response body can be parsed. The response format returned depends on the Accept header.

Table 2 - Expected response format based on "Accept" header

Accept Header (media type) Response Format
application/atom+xml Atom feed or entry response
application/xml XML response
application/json JSON response
all other media types XML response (default)



Here is the format of the error message construct, represented in XML and JSON format.
 

XML error message construct

<error>
   <code type="error type goes here">error code goes here</code>
   <message>brief description of the error</message>
   <detail>how to resolve the error, expected values, etc.</detail>
 </error>

JSON error message construct

{
    "code": {
        "value": "error code goes here",
        "type": "error type goes here"
    },
    "message": "brief description of the error",
    "detail": "how to resolve the error, expected values, etc."
}

Whether receiving the error message in JSON or XML format, you can expect these elements to be delivered consistently:

Table 3 - Error Message Elements

Elements Description Required
code a code unique to each error offered by a specific API
attribute:
  • type - {"http","application"}
Yes
message a text message describing the error No
detail how to resolve the error, expected elements, other helpful information No


An optional 'type' attribute is available on the 'code' element with values of {"http","application"}
 

  • The type="http" attribute is used when the 'code' element indicates an HTTP response status code.
  • The type="application" attribute is used when the 'code' element refers to an application designated code.


Let's consider two examples. First error we might run into during development - incorrectly structured urls or missing pieces. Then we'll consider errors from data which are likely to occur in production.

Example - Errors During Development

When developing against a new service, it is common to forget an element or otherwise submit a malformed request. In this example, I am requesting a bibliographic record from the Metadata API to read a bibliographic resource, and must apply HMAC Authentication to access this protected resource.

A request to this service has this form:

https://worldcat.org/bib/data/{oclcNumber}?inst={inst}&classificationScheme={scheme}&holdingLibraryCode={holdingLibraryCode}

It is common to make mistakes when calling an unfamiliar service. Let's look at the error responses as we work to get data for bibliographic record 823520553.

1. Missing elements from the Authorization header and a missing Accept header.

For this test, we'll fail to set the Accept header and omit the principalID and principalIDNS from the Authorization header to see what comes back. Note that omitting the Accept header is not error, it just causes the response type to default to "application/xml;charset=UTF-8". Here is my request:

GET http://www.worldcat.org/bib/data/823520553?inst={Institution ID}&classificationScheme=LibraryOfCongress&holdingLibraryCode=MAIN HTTP/1.1

Here are the headers (my program generated the Authorization header - see HMAC Authentication for details.

Authorization: http://www.worldcat.org/wskey/v2/hmac/v1
    clientId="{WSKey public key}",
    timestamp="1380638086",
    nonce="8fe0503b",
    signature="0PZRJn9TX3I7EpOQJuFSOSDrAZ5+qboYy8u9wFrcN1s="

And here is the response - I got a 400 back, and an error message in XML format. Because I didn't specify an "accept" header in my request, the result defaulted to "application/xml;charset=UTF-8". The body contains the error code's value, it's type, the error message and the error message detail.

HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: application/xml;charset=UTF-8
Content-Length: 285
Date: Tue, 01 Oct 2013 14:34:46 GMT
Connection: close

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <error xmlns="http://www.worldcat.org/xmlschemas/response">
        <code type="http">
            400
        </code>
        <message>
            Unable to retrieve user permissions due to bad request
        </message>
        <detail>
            PrincipalID and PrincipalIDNS values are missing.
        </detail>
    </error>

2. Missing elements only.

This time, I've added "application/json" as our Accept header, but I am still omitting the principalID and principalIDNS elements from the Authorization header:

GET http://www.worldcat.org/bib/data/823520553?inst={Institution Id}&classificationScheme=LibraryOfCongress&holdingLibraryCode=MAIN HTTP/1.1

Here are the headers:

accept: application/json

Authorization: http://www.worldcat.org/wskey/v2/hmac/v1
    clientId="{WSKey public key}",
    timestamp="1380637781",
    nonce="992bbb74",
    signature="Vvy41R6iNIaPWdB6Vnh2HULUolGi6qCHqb5kC27trqg="

And the response comes back with an HTTP error code of 400, but the response body is in JSON format.

HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Content-Length: 166
Date: Tue, 01 Oct 2013 14:29:42 GMT
Connection: close

{
    "code": {
        "value": "400",
        "type": "http"
    },
    "message": "Unable to retrieve user permissions due to bad request",
    "detail": "PrincipalID and PrincipalIDNS values are missing."
}

3. A successful request.

Time to do it right. I've settled on application/json as the Accept type and remembered to add the principalID and principalIDNS to the Authorization header.

GET http://www.worldcat.org/bib/data/823520553?inst={Institution Id}&classificationScheme=LibraryOfCongress&holdingLibraryCode=MAIN HTTP/1.1

The request headers:

accept: application/json

Authorization: http://www.worldcat.org/wskey/v2/hmac/v1
    clientId="{WSKey public key}",
    timestamp="1380637154",
    nonce="f0d44000",
    signature="xUqw8U3LPRQ5opsras0wcndmtZTzM+KOQSPwPobZ9qw=",
    principalID="{principal ID}",
    principalIDNS="{principal IDNS}"

Success!

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 01 Oct 2013 14:19:15 GMT

{
    ...
}

I find it helpful to work with new API's in a restful client while working out the request details. In the above example, the error messages provided guidance as I worked to build a successful request.

Example - Errors Encountered in Production

After you've developed your service, you have the HTTP request URL elements and headers properly specified. But there are some problems in production you cannot control. We consider some of these, and see that error handling is the same as the developer examples above. Because the examples are similar to the successful request in item #3 above, with just bad data inserted, I'll just show the responses.

1. Invalid Institution Id (403)

Here I tried a GET request against an InstitutionID that had a typo in it. Since I am only authorized for specific institutions, we are headed for trouble:

HTTP/1.1 403 Forbidden
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Content-Length: 148
Date: Tue, 01 Oct 2013 15:07:26 GMT

{
    "code": {
        "value": "WS-403",
        "type": "application"
    },
    "message": "The Institution Identifier provided does not match the WSKey credentials.",
    "detail": null
}

Why did I get 403 forbidden? Because the service checked the InsitutionID against the list of InsitutionID's assigned to my WSKey and couldn't find it. So whether this error is due to an InsitutionID typo, or a deliberate attempt to read a record from an institution that I'm not authorized for, it is a security error.

2. Invalid Classification Scheme (400)

Based on the previous error message, I fixed the institutionID, but this time I've messed up the classificationScheme element. Instead of the valid "LibraryOfCongress", I submitted "LibraryOfDublin".

HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Content-Length: 276
Date: Tue, 01 Oct 2013 15:20:25 GMT
Connection: close

{
    "code": {
        "value": "WS-404",
        "type": "application"
    },
    "message": "Invalid classification scheme. Valid schemes are: DeweyDecimal, LibraryOfCongress,
    NationalLibraryOfMedicine, NationalAgriculturalLibrary, GovernmentDocument, UniversalDecimal,
    CanadianNationalLibrary.",
    "detail": null
}

This time we got a 400 error along with a helpful error message. Because we did not get a 403, we know our request was authorized - but the service did not like one of the elements we passed.

Error Handling Resources

Conclusion

OCLC Web Services offer descriptive error messages in a format determined by the Accept header. You can make use of these messages for debugging HTTP requests, or in production when dealing with incorrect user data. Each API should be consulted for its specific elements and error messages, but the error message format is consistent across all services.

Note: This is the first blog post from George Campbell, and we're happy to add his voice to the Developer Network News. George is a web developer on our Platform Team. His focus is on mobile app development with iOS, Android and popular app frameworks like Cordova, with a specific interest in applying OCLC Web Services to mobile devices in library applications.

  • George Campbell

    George Campbell

    Senior Software Engineer

    O: 614-764-6227

We are a worldwide library cooperative, owned, governed and sustained by members since 1967. Our public purpose is a statement of commitment to each other—that we will work together to improve access to the information held in libraries around the globe, and find ways to reduce costs for libraries through collaboration. Learn more »