White Box技術部

WEB開発のあれこれ(と何か)

【Groovy/ShangriLa】JsonSlurperとHTTPBuilderの使い方サンプル

引き続きShangriLaを例にしていますが、今度はGroovyでGETリクエストの実行と返却されたJSON文字列を処理してみました。

おや、Gradleサイトの様子が・・・!

README書くためにGradleのサイトに行ったところ、サイトがリニューアルしていました。

どうもgradle.comというコミュニティサイトっぽいものを作るから先行登録してね、 みたいなことを通知したいためのようです。 今のところサイトには簡単なGradleの使い方が載ってるぐらいで、 ほとんど情報はなく、このサイトがどうなっていくのかは不明です。

自分としては、ただGradleのインストール手順までの遷移がわかり辛くなったな、と感じただけでした。

なので、インストール手順が書いてあるページを以下にリンクしておきます。

HTTPBuilderでのGET方法

GroovyでHTTP通信をするのであれば、HTTPBuilderを使うのが良いと思います。

github.com

HttpBuilderの設定

build.gradleのdependenciesにhttp-builderを追加すると、対象のGradleプロジェクトから利用可能になります。

  • build.gradle
repositories {
    mavenCentral()
}

dependencies {
    compile ('org.codehaus.groovy:groovy-all:2.4.5') {transitive = false}

    compile 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.1'
}

以前はbuild.gradleのrepositoriesに、HTTPBuilderが置いてあるMavenリポジトリのパスを2つ追記し、 以下のようにする必要がありましたが、現在はこの指定は不要になっているようです。

  • 昔の書き方
repositories {
    mavenCentral()
    maven {
        // for HTTP Builder
        url "http://repository.codehaus.org"
        url "http://snapshots.repository.codehaus.org"
    }
}

GETリクエストの送信方法

HTTPBuilderクラスのgetメソッドを呼ぶ方法と、requestメソッドで実行する方法があります。

記載の通りに実行すればGETリクエストを送信できますが、せっかくなので色々試してみました。

requestメソッドの利用方法

公式の記述のように、HTTPBuilderクラスの引数を指定せずに、requestメソッドの第1引数にホスト名を渡す方法でもできますが、省略して以下のように書くこともできます。

def http = new HTTPBuilder("http://api.moemoe.tokyo")
def resJsonText = http.request(GET, TEXT) {
    uri.path = '/anime/v1/master/cours'
    headers.Accept = 'application/json'
  
    response.success = { resp, json ->
        assert resp.status == 200
        def jsonString = json.text
        println("GET /anime/v1/master/cours json response: $jsonString")
        jsonString
    }

    response.'404' = { resp -> println "Access denied" }
    response.failure = { resp -> println "Unexpected failure: ${resp.statusLine}" }
}

ヘッダー情報も付ける必要がなければ付けなくても動作します。もちろん付けたければ公式のように色々付けれます。

ちなみにresponse.'404'response.failureのときのresJsonTextの戻り値はnullになります。何も返してないですからね。

はまりポイント

HTTPBuilderのパラメータや、requestメソッドの第1引数にホスト名以降を書くと、404になります。

また、uriの指定で先頭に/がないとエラーになります。

getメソッドの利用方法

これは公式にある通りに書けば大丈夫なので、上記のサンプルを書き直すと以下のような感じになります。

def http = new HTTPBuilder("http://api.moemoe.tokyo")
def resJsonText = http.get(
    path : '/anime/v1/master/cours',
    contentType : TEXT) { resp, json ->
        if (resp.status < 400) {
            def jsonString = json.text
            println("GET /anime/v1/master/cours json response: $jsonString")
            jsonString
        }
        else if (resp.status == 404) {
            println "Access denied"
        }
        else {
            println "Unexpected failure: ${resp.statusLine}"
        }
    }

結果を受け取ることだけを考えると記述量が減って簡単ですが、リクエストの成功と失敗の判断を自前でやることになるので、状況によって使い分けるべきですね。

switchで書いた方が綺麗かも。

GroovyでJSONを扱う

次に返却値のJSONを処理するために、groovy.jsonのJsonSlurperクラスを使います。
Scalaを書いた後だったからなのか、これ、すごく便利に感じました。Groovyの最強感がすごい。

JSON文字列をGroovyで扱えるJSONオブジェクトに変換する

JsonSlurperを使ってJSONオブジェクトを作るのはとても簡単です。
JsonSlurper#parseTextメソッドJSON文字列を渡すだけで完了します。

def jsonSlurper = new JsonSlurper()
def resJsonObj = jsonSlurper.parseText('{"3":{"id":3,"year":2014,"cours":3}}')

こうして作成したJSONオブジェクトは、JSONデータをMapで表現するため、直感的に扱うことができます。
Mapなので、キーを得たい場合はresJsonObj.key、値を得たい場合はresJsonObj.valueで取得できますし、 キーを指定して値を得たい場合はassert resJsonObj.value.year == 2014のように、 キーの要素で指定するだけです。ポイントはvalue値がダブルクォート無しの数値であれば、ちゃんと数値型で取り出せるというところでしょうか。なので文字列比較にしていると失敗します。

今回のサンプルコード

今回の解説で利用したサンプルコードのベースとなるGroovyプロジェクトは、以下になります。こっちではもうちょっと色々やっているので、ぜひこちらもご覧ください。

github.com

正月早々

帰省中にプログラミングしようと思っていたのですが、このサンプルを書いたところで風邪でダウンしてしまいました。 今年は家に引きこもるのもほどほどにして、少し体力をつけて病気に負けないようにしたいです。

そして、久しぶりにGroovyでコード書きましたが、びっくりするぐらいに書きやすかったです、Groovy。
前回、ScalaJSON操作するのに四苦八苦したことを考えると、JsonSlurperの直感性は感動的でした。
なかなかプロダクトで使うのは難しい言語ですが、個人的にはこれからも使っていくので、都度トピックを紹介させて頂こうと思っています。

もし興味を持っていただけたのであれば、試しに今まで書いたJavaのコードをGroovyに変換してみてください。そうすると魅力に気付きやすいかと思います。

そして慣れてきたら、是非Spockを使ってGroovyでテストコードを書きましょう!