use curl for api documentation
I’ve been working quite a bit with the rest plugin for Struts2. The really nice thing about this plugin is the way it cleans up Struts URLs. Makes them more rails-like. I chuckled when depressed programmer suggested that struts2 is “WebWork on drugs.” I hate struts2. I really do.
Anyway, I have stripped down an AccountController to show just the POST service. In reality, the create() method is wired to a middle tier service that authenticates username, password pairs then updates session attributes with member id and other bits of persistent session data I need.
// imports omitted @Results({ @Result( name = "success", type = ServletActionRedirectResult.class, value = "account") }) public class AccountController extends ActionSupport { private String username; private String password; // getters/setters omitted public AccountController() { } public HttpHeaders index() { return notImplemented(); } public HttpHeaders show() { return notImplemented(); } public HttpHeaders edit() { return notImplemented(); } public HttpHeaders editNew() { return notImplemented(); } public HttpHeaders update() { return notImplemented(); } public HttpHeaders destroy() { return notImplemented(); } public HttpHeaders create() { int status = (username.equals("alice") && password.equals("restaurant")) ? HttpServletResponse.SC_ACCEPTED : HttpServletResponse.SC_UNAUTHORIZED; return new DefaultHttpHeaders().withStatus(status); } private DefaultHttpHeaders notImplemented() { return new DefaultHttpHeaders() .withStatus(HttpServletResponse.SC_NOT_IMPLEMENTED); } }
Note that I only return HTTP headers; the body content will always be empty.
I have found curl invaluable for documenting the API. This is a simple case but consider a much more complicated system with dozens of URLs and each URL implements many of the HTTP methods (including PUT and DELETE).
Third party developers are the bane of the support engineer. First, few people read documentation. They skim the material and furiously code. When their software fails, they file a bug that the API is broken. Usually, the API isn’t broken; the developer simply did not understand the API.
I subscribe to the agile manifesto value of “working software over comprehensive documentation.” In my work, I have found that a few curl examples clears up most of these issues. For example, to exercise the create() method in the AccountController, simply post a form.
curl \ --request POST \ --include \ --url "http://ws.example.com/account" \ --form "username=alice" \ --form "password=restaurant" \ --cookie-jar "cookies" \ --cookie "cookies"
I like to add the “–include” flag as it displays some extra header information. When I get a support call, I have the developer trot out the “documentation” curl examples and open a bash shell. This, of course, drives the Windows guys nuts–to which I reply, “buck up.” We work through the exercise of getting the http request working with the curl example. Then a miracle occurs. The developer now has a working example on their machine from which to re-examine their code.
A final note. The “–cookie-jar” and “–cookie” parameters will handle cookies between the web server and your curl commands. In otherwords, you can login to a website and these parameters will store your authenticated session id in a file. The file in this example is named “cookies” but it can be legal filename. You can then make subsequent calls to URLs, passing the cookies (and, therefore, the session id) back up to the server.
For example, to upload your avatar picture to your new social network, first login using the curl command above. This establishes an authenticated session. Then post your picture using the curl command below, making sure you pass the cookies back up.
curl \ --request POST \ --include \ --url "http://ws.example.com/avatar" \ --form "avatar=@somepix.jpg" \ --cookie-jar "cookies" \ --cookie "cookies"
Finally, if you need to add a description, publish the curl command as part of a bash script. For example,
#!/bin/bash # 1. you must login before you can upload the avatar # 2. the web server will reject any avatar exceeding 2MB # 3. do not forget the '@' symbol, a common mistake # 4. do not forget to include --cookie and --cookie-jar curl \ --request POST \ --include \ --url "http://ws.example.com/avatar" \ --form "avatar=@somepix.jpg" \ --cookie-jar "cookies" \ --cookie "cookies"
Good luck!