Yesterday I introduced CooperDB, the first distributed, share-nothing database that is fully partition tolerant, highly available, and immediately consistent. I promised to follow up with a post on the creation of CooperDB - which is what you are reading now.
CooperDB has a very straightforward REST interface. It supports two methods:
- POST <path> - Store any payload of any content type at the specified path. Returns HTTP status code 201 - Created.
- GET <path> - Retrieve the payload previously stored at the specified path. Returns HTTP status code 404 - Not Found.
Remember, one of the unique features of CooperDB is that you can send whatever you want to it to store it, and then you will never be able to find it again. This key feature is what makes it possible to be partition tolerant, highly available, and immediately consistent all at the same time.
Zoomulus Servers seems a great place to start, since it was designed to make it super easy to create a simple web service as quickly as possible. It turned out to be quite straightforward. Here are the steps:
I created a new Maven project, and added
com.zoomulus.servers as a dependency:
At the time of this writing, version 0.0.2 of
com.zoomulus.servers is the latest available on Sonatype so I’ll use that for now.
Create the server
CooperDB is essentially an HTTP web server as defined in
com.zoomulus.servers. Creating the server is as simple as extending
Using Guice to create our server class allows us to inject the port number and the
HttpResponder subclass which will handle the requests. Zoomulus Servers expects this and leverages it to make creating a server really easy. The
CooperDBServer constructor simply passes the port and the injector along to the library underneath.
Define the Guice module
We used the class
CooperDBServerModule as the Guice module for our dependency injection in the
main function of
CooperDBServer above. That module needs to define the port number we will listen on and our
HttpResponder subclass to use:
Define the HttpResponder
The module bound
HttpResponder to the class
CooperDBServerResponder which is the last thing we need to define. Remember the requirements:
- It can accept a POST on any path and respond with 201 - Created.
- It can accept a GET on any previously POSTed path and respond with 404 - Not Found.
- Any other method is unsupported.
Of course, if a GET is received on a path that was not previously posted, the answer would also be 404 - Not Found, which makes this quite a bit easier.
Here’s the responder:
There are three methods we have to implement from
haveMatchingResourcebasically tells the library “I know what to do with this request resource” (or path). Since we know how to handle everything, we return
truehere. Because the library will automatically generate a 404 if
false, we could also have inspected the request and returned
falsehere if it was a GET method. Either approach would work.
isSupportedMethodtells the library “I know how to handle this request method”. We support two methods - GET and POST.
generateResponseactually puts the response together that is sent back from the server. This is easy:
- If it is a GET, return 404
- If it is a POST, return 201
- If it is anything else (which should not happen), return 405
That’s all there is to it.
CooperDB is a fun joke, but it does do one important thing: It shows just how easy it is to create a functioning web service using the Zoomulus Servers library. Over time I’ll use this to evolve them both into something even more easy to use.
CooperDB is available on GitHub.