About a month ago I asked what people would use to build a new Web service from scratch, without providing any real details on what the application would do. People seemed to all agree that basing the service on JSON was the best way to go, and that’s the route I took, so I thought I’d write it up.
In this case, I have a PHP front end talking to a Java back end that uses Spring and Hibernate. The application in question is the administrative console for a test harness for a SOAP Web service. We use a third party SOAP service and needed the ability to provide responses that are guaranteed to always be the same for the purpose of creating tests. So my test harness stands in for the third party service, requiring only a URL change, and returns the data managed via the client application to which my question referred.
The application itself is very simple — it’s a single table with a lookup mechanism. The client enables users to find and edit individual records from the table. I needed four basic operations:
- Search for records
- Retrieve a single record
- Update a record
- Create a record
- Delete a record
This is a Java application that uses Spring and Spring MVC. I use Spring’s Web Services support for the SOAP stuff, but it wasn’t worth it to bother with that for the administrative client. So instead I mapped every URL ending in
.json to a Spring
DispatcherServlet. Like all sensible Java developers who’ve worked in Rails, I hate configuration in general and XML configuration files in particular. So I used Spring’s
ControllerClassNameHandlerMapping, which extracts the path from the URL and maps it to a Spring controller.
So a path like
/myapp/responses/search.json calls the
search() method in the
ResponsesController class. Simple.
I won’t go into the boring details of my implementation, other than to talk about how I’m passing the messages back and forth. The client uses standard form submission (name and value pairs) to submit the data, and expects to get JSON back. So in the case of search, I extract the field name and query value, go to the database and run a query to retrieve the records in question, and then package them up and encode them using JSON to be sent back to the client.
The JSON encoding is handled by Google’s GSON library, and it’s ridiculously simple. It accepts a plain Java object, and serializes it and all of its children using reflection. Any properties that are null are omitted. So for my application, I created a wrapper object that was well-suited to being encoded using GSON. It includes a hash for error messages, a property for a single response object, and a collection of response objects for search results.
Then I created a view for Spring called
SimpleGsonView, which accepts a wrapper (or any object), encodes it using GSON, and then sends the results to the client. Here’s the whole thing:
protected void renderMergedOutputModel(Map aMap,
HttpServletResponse aResponse) throws Exception
Object wrapper = aMap.get("wrapper");
Gson gson = new Gson();
ServletOutputStream out = aResponse.getOutputStream();
One thing you may notice is that I do a search and replace on the JSON. It removes all occurrences of
\n from the encoded data. That’s a hack to get around a client side bug that I got tired of trying to fix. I’ll talk about that later.
So for this application, to add new functionality, I just add a new method to my controller, process the input parameters and put the correct results in the wrapper, and then pass that to the view I created. Very simple. I added an autocomplete feature to the search page, and this is all I had to do to add support for it on the back end:
public ModelAndView complete(HttpServletRequest aRequest,
String searchField = aRequest.getParameter("field");
String searchQuery = aRequest.getParameter("query");
List<String> results = Collections.emptyList();
results = getFirstNameCompletions(searchQuery);
else if (searchField.equals(LAST_NAME))
results = getLastNameCompletions(searchQuery);
else if (searchField.equals(KEY))
results = getKeyCompletions(searchQuery);
else if (searchField.equals(ZIP))
results = getZipCompletions(searchQuery);
return new ModelAndView(new SimpleGsonView(), "wrapper",
The methods to retrieve the data are in another class, but I removed the reference to it for simplicity.
So that’s the server piece. I could have done more to make it RESTful but since the service is just for me, I went with the simplest possible approach.
For legacy reasons the client is a PHP application, and I decided to use jQuery and a little PHP to implement the client features. Here’s how each operation is implemented:
Search: The search feature is pure jQuery. The home page for the client has a search form on it with a pulldown of fields that can be searched and a text box for the search terms. I used the autocomplete feature from jQuery UI to make the search form a bit friendlier. I catch the submission of the search from (or the selection of an item in the list provided by autocomplete) and submit the results to the server using jQuery’s
getJSON() method. Then I create a table on the page with the search results in it.
\n from the XML, it worked, so I went with it.
Create a record: This form uses jQuery’s
post() method to submit the contents of the form to the server. If the request returns a successful result, it redirects the user to the detail page for the new item. If it doesn’t, it displays the errors included in the result.
Update a record: This form works just like the create form.
Delete a record: This is the simplest operation of all. It submits the key to be deleted, and the server simply returns true or false.
Update: Read this excellent follow-up from Sam Ruby as well.