A Webmachine-like framework for Clojure
Clojure
Pull request Compare This branch is 114 commits behind cmiles74:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src/com/tnrglobal/bishop
test/com/tnrglobal/bishop/test
.gitignore
GPL-LICENSE.txt
LICENSE.org
MIT-LICENSE.txt
README.org
project.clj

README.org

Bishop is a Webmachine-like framework for Clojure. The primary goal of this project is to make it much easier to construct a clean, HTTP 1.1 compliant web-based API. With this ground-work laid, it will be much easier for the developer to construct REST-ful or even HATEOAS compliant services.

Warning: Work In Progress

Be warned that this is a work in progress! Not only is this project wholly untested, it’s not even complete. I am earnestly working on this project and expect to finish development on an alpha version in April of 2012.

Aren’t There Other Projects that Do This?

Yes, there are several other projects that are looking to do this very same thing. The ones that I am aware of are…

This project has slightly different goals from those mentioned above. For one, this project isn’t particularly interested in exposing a nice interface to Java code. Our primary concern is to make things easier for the Clojure developer.

Plugboard is constructed on top of the excellent Compojure library which in turn builds on Ring, this project builds on top of Ring directly. The web APIs that I have constructed so far have been coded on Ring and I don’t want to pull Compojure into the mix.

How Does it Work?

Well, things will be in flux until the first version of the library is completed. So there’s that.

Anyway, let’s say you have a function that will say “Hello” to people.

(defn hello
  [name]
  (str "Hello " name "!"))

We can then define a resource that says “Hello” in HTML or JSON.

(def hello-resource
  (bishop/resource
    {"text/html" (fn [request]
                    (hiccup/html
                      [:p (hello (:name (:path-info request)))]))}

    {"text/json" (fn [request]
                    (clj-json/generate-string
                      {:message (hello (:name (:path-info request)))}))}))

This resource can return either HTML or JSON content, depending on the headers of the request. It expects to have a value in the “path-info” map under the “:name” key. This comes from the routing.

(def routes
  {["hello" :name] hello-resource
   ["*"] (bishop/halt-resource 404)})

We route incoming request for “/hello/something” to our “hello-resource” functions, anything else will result in sending a “404” code to the client. Bishop will parse the route and the request’s URI to populate the “path-info” map for your application, the goal is to do it in the same way that Webmachine handles dispatch.

Lastly, you can add this as your Ring handler function.

(def app
  (-> (bishop/handler routes)
      (wrap-params)
      (wrap-stacktrace)))

Aside from parsing the URI and matching it to the route, Bishop is doing a lot of other work as well. It will cover all of the behavior in this HTTP 1.1 flow chart. In this instance, Bishop is…

  • Parsing the client URI and route, then populating the “path-info” map
  • Verifying that the client is trying to either GET or HEAD the resource.
  • Making sure that the length of the URI isn’t totally nutty.
  • Verifying that our resource can accept either a GET or a HEAD request.
  • Checking to see if there are authorization headers if our resource requires them (which it does not).
  • Selecting the appropriate content type to provide to the client and sending the appropriate error if the client asks for a resource that we do not provide.

And so on.

Sample Application

I have put a small, fairly poor sample application together to make sure that the library builds and mostly functions. If you’re interested, you are welcome to take a look at it.

https://github.com/tnr-global/bishop-sample