DougBreaux 270007SMYJ Visits (5430)
Discussing with a customer about how to return errors from our "RESTish" API. (Which has existed for a long time, well predating at least our current awareness of good HTTP API practices). Thought I'd document a few things while they're fresh in my memory...
HTTP Response Codes
I'm already a believer in usin
My first cut assumed that it would be normal/reasonable for error responses to be a plain text content type. After all, they're just a status code and maybe an explanatory message.
But after looking more at other APIs, and thinking about how a caller would most easily process replies, it seems better and common to use the same Content Type for both normal responses and errors. So that was the next change. Whatever Content Type the caller has requested (our API supports either XML or JSON), that's the format of error responses as well now.
Single or Multiple Errors?
I thought the norm I'd seen, as a caller, was always a single error returned, so this is what I implemented. But when adding some more sophisticated input field validation (via
That presents 3 options:
Option 1 fit more with what I thought was normal. And, since for an API, it seems normal to me that input validation errors will often or even usually be worked out and removed during development & integration, this was the direction I was inclined to choose. That is, I don't normally expect an application that is using an API to actually rely solely on the API to do any kind of input limi
Option 2 is what my customer wanted, so this is ultimately what I did. Even though he probably won't be the only customer, he's the first and the only for the foreseeable future. Further, after a little research, I determined that both options 1 and 2 seem to be in common use, with no clearly preferred approach.
To me the downside of this approach is having to semantically decide how to handle things differently, depending on whether there are one or more errors. Or even deciding which calls in which states might truly produce more than one, and which wouldn't.
Option 3 I did see some examples of, in articles describing how to design an API, but I haven't yet found any major APIs using that approach. In these examples, the use case for wanting to report multiple errors at once is the very one I hit: input validation. But being able to handle either case seems an unnecessary complication.
My original reason for making this post was to capture the places I'd found that were examples of what APIs did. So, to complete that goal:
We've recently had a need to accept files submitted by a partner and perform some processing on them, with the partner returning later to retrieve the results. Rather than the "old", standard approach of using something like sftp and regularly kicking off a cron job to look for input files, this seemed like a good case for a Web Service.
And IMO REST style services are simpler to produce (particularly with standard APIs like JAX-RS), consume, and test, and further are a good fit for this particular scenario. (See the excellent book REST
I decided to support the URL "/batch", as an HTTP POST of standard "mul
I should say, I decided to propose this approach and then go see if I could make it happen in a straightforward way. I wasn't sure if submitting files this way was normal enough to be easily supported by JAX-RS and/or WebSphere.
It turns out this is supported by JAX-RS in WebSphere, with a few different mechanisms. Right there in the official IBM Knowledge Center documentation, (almost) everything I needed to know:
So go read that, I'm done :-)
... well, ok, I'll summarize and note a few things, while I'm here.
Generic JAX-RS approach
I generally prefer to stick to the specs, not using any server-specific or impl
With WebSphere, this uploads the file to a temporary location, and gives it a generated file name. (On my Windows development system, the location seems to be my Windows %TEMP% directory.)
However, I'd prefer to prescriptively set the upload directory (so I don't have to later copy it to a more "permanent" location), and I really want the original file's name (among other things, so I can detect when the same file is inadvertently submitted again).
Because of these requirements, I needed to look for another approach.
WebSphere-specific (Apache Wink) approach
It turns out the last example on that
This approach looks more like:
And involves looping through the parts and parsing the HTTP Headers to get the Cont
In addition to the above WebSphere link, also see Apac
I'll note a few problematic behaviors we discovered during the implementation and testing.
Internet Explorer and file input elements
Further, the java
Granted, this service won't normally be called from a browser and HTML page, but during testing, it sometimes is. And even there, using a different browser is acceptable. But still, if it wasn't too much work, I'd prefer to handle this more robustly "just in case".
.NET client error on the GET request
Our partner appears to be using a C# .NET client, and even after he had success submitting a file to our POST URL, he was getting this error upon calling our GET URL from Http
“The server committed a protocol violation. Sect
I've been trying to connect to a customer's Web Service (from within WebSphere 6.1, but that's a different topic) and having some problems getting the security to work (another different topic), so I've desperately wanted an https-capable traffic monitor/proxy.
After trying the one built into RAD (which successfully passes the https requests, but displays them as encrypted garbage), Apache tcpmon (no SSL), membrane-monitor (seemed to not respond at all and I couldn't tell why), and Wireshark (looked too tedious to get working with SSL), I eventually got soapUI's HTTP Monitor working, although not without some non-obvious setup there either. So I'm going to document that setup here.
Trust the Service Endpoint
First, you'll need a jks TrustStore where you can place the public key of the server which hosts the https-protected Service you're going to call. You can use a tool like the GUI ikeyman, included with WebSphere, or the command-line keytool, included with your JRE, to do this.
Launch the HTTP Monitor
Next, it seemed fairly obvious what to do in soapUI. Right-click on a project and "Launch HTTP Monitor". You're presented with the following dialog:
To do https/SSL, you need to select HTTP Tunnel rather than HTTP Proxy. Set the Port to the local port your client is going to hit, and the endpoint to the remote service URL you're ultimately calling.
Then go to the Security tab:
Initially, all I had was the aforementioned TrustStore configured here in the HTTP tunnel - TrustStore and TrustStore Password fields. This allows the HTTP Monitor to talk SSL to the remote Service.
However, when I started the monitor with those settings, I received a cryptic dialog, "Error starting monitor: C:\Program File
I suspected Windows authority problems or path problems, but nothing seemed to resolve those, so I tried running the soapui.bat script from a command-prompt rather than the soapUI desktop shortcut, and then I saw the following prompts:
jetty.ssl.password : jett
Ahah! Google does find something relevant there.
HTTP Monitor Server Certificate
HTTP Monitor needs its own SSL certificate (private key) and KeyStore in order to also talk SSL to your client application, which I should have realized. Then, of course, your client environment will have to import the public portion of that certificate into its TrustStore as well. But the less obvious detail is that this private key must use the alias "jetty" (as soapUI is using the Jetty server under the covers).
So again using keytool (or ikeyman), this time to generate a private/public key certificate pair with the alias "jetty", create the KeyStore that is referenced in the HTTP tunnel - KeyStore, Password, and KeyPassword fields. (Note the two properties listed in the prompts above.) Here's the keytool command I actually used:
jre\bin\keytool -genkeypair -alias jetty -keystore soapui.jks
Now complete the remaining Security fields and click "OK":
You'll have an SSL Tunnel listening on your local port, and you'll be able to see SOAP requests and responses sent through that local URL.
If you've ever wanted to know what kind of HTTP Request headers might be coming from a client or some intermediate proxy, here's a simple JSP you can manually deploy to your JEE Web Application to see a list.