Extracting data from JIRA using Clojure and REST
March 2, 2012 at 10:45 pm | Posted in Clojure, Programming | 2 CommentsI have previously written two posts about getting data from JIRA. In the first one I described how you can do that in Ruby. In the other one I used JavaScript to import JIRA data directly into Google Documents. Both methods worked and both heavily rely on the SOAP interface that JIRA offers. However, as of JIRA version 5 a REST interface is the preferred way. So I decided to try this using Clojure.

Initially this seemed to be very straightforward. I have been using a well-written Clojure lib that provides an Async Http Client in the past to extract for example Twitter stream data. So it would only take a couple of minutes to setup a new Clojure project, use basic authentication to connect to a JIRA instance at work and extract all the data I needed. Well, it didn’t.
My first goal was to list all projects. On the commandline I successfully used:
$ curl -u user:password https://intranet.mycompany.com/jira/rest/api/latest/project
In Clojure, using the aforementioned library that would become:
(ns jira.core (:require [http.async.client :as c]) (:use [clojure.data.jsonnly (read-json)])) (def jira-project-url "https://intranet.mycompany.com/jira/rest/api/latest/project") (defn get-all-projects "Return all projects from JIRA" [] (with-open [client (c/create-client) :auth {:user "user" :password "password"}] (let [response (c/GET client jira-project-url)] (c/await response) (read-json (c/string response)))))
However, this always returns an empty vector and I still haven’t found out why. So I started to looking for an alternative. I imagined a better way would be to setup a session, retrieve a session cookie and use that for subsequent calls. I’ll begin with showing the end result:
(ns jira.core (:require [http.async.client :as c]) (:use [clojure.data.jsonnly (read-json json-str)])) (def session-url "https://intranet.mycompany.com/jira/rest/auth/latest/session") (defn login "Login into JIRA" [username password] (with-open [client (c/create-client)] (let [response (c/POST client session-url :headers {:Content-Type "application/json"} :body (json-str {:username username :password password}))] (c/await response) (c/cookies response))))
This is more or less the Clojure equivalent of:
$ curl -c cookie_jar -H “Content-Type: application/json” -d ‘{“username” : “user”, “password” : “password”}’ https://intranet.mycompany.com/jira/rest/auth/latest/session
With this implementation of login that returns a session cookie I rewrote get-all-projects to:
(defn get-all-projects
"Return all projects from JIRA"
[cookies]
(with-open [client (c/create-client)]
(let [response (c/GET client jira-project-url :cookies cookies)]
(c/await response)
(read-json (c/string response)))))
This version works perfectly and enables me to write compact code like:
(def session (login "user" "password")) (map :name (get-all-projects session))
This example generates a map with the abbreviated names of all projects currently in JIRA.
Right now the code is mostly proof of concept. As soon as it is cleaned up a bit I will start a new project on GitHub to share it. Enjoy!
2 Comments »
RSS feed for comments on this post. TrackBack URI
Leave a Reply
Blog at WordPress.com. | Theme: Pool by Borja Fernandez.
Entries and comments feeds.
In your first code snippet, on lines 10-11, didn’t you specify the auth information in the wrong area?
https://gist.github.com/2596862
Comment by mdeboard1— May 4, 2012 #
I was trying to do something similar, but authenticating to Jenkins using http basic auth. Seems I needed the :preemptive true option to :auth.
https://gist.github.com/2720716
Comment by petespitstop— May 17, 2012 #