CLOVER🍀

That was when it all began.

Groovyで使うHTTPクライアントを、HTTPBuilderからJAX-RS Clientに移った話

最近、簡単にスクリプト的なHTTPクライアントを書く機会があって、Groovyで書こうとしたのですが…普段はHTTPBuilderを使っているのですが、ちょっと変えることにしました。

HTTPBuilder
https://github.com/jgritman/httpbuilder

Document
https://github.com/jgritman/httpbuilder/wiki

Codehausのサイト、なくなっちゃいましたね。そちらに行こうとすると、GitHubの方に飛ばされるようになっていました。更新もあまりされていないようですし、Grapeと一緒に使ってハマったこともあったので、ここは思い切って乗り換えることにしました。

乗り換え先は、JAX-RS Clientで。

今回は、JSONリクエストを送信するものとして書いてみます。

とりあえず、書いてみたのはこんな感じ。
client.groovy

@Grab('org.jboss.resteasy:resteasy-client:3.0.11.Final')
@Grab('org.jboss.resteasy:resteasy-jackson2-provider:3.0.11.Final')
import javax.ws.rs.client.Client
import javax.ws.rs.client.ClientBuilder
import javax.ws.rs.client.Entity

import groovy.json.JsonBuilder

def client = ClientBuilder.newBuilder().build()

def builder = new JsonBuilder()
builder.people {
  person {
    firstName 'Taro'
    lastName 'Tanaka'
    address {
      country 'Japan'
      prefecture 'Tokyo'
    }
  }
}

def requestEntity = builder.toString()

try {
  def response =
    client
    .target("http://localhost:8080/message")
    .request()
    .put(Entity.json(requestEntity))

  def responseEntity = response.readEntity(LinkedHashMap)

  assert responseEntity['message'] == 'こんにちは [Tanaka Taro]!'

  response.close()
} finally {
  client.close()
}

JAX-RSの実装には、RESTEasyを使用しています。

JSONリクエストの作成には、GroovyのJsonBuilderを使用しました。

def builder = new JsonBuilder()
builder.people {
  person {
    firstName 'Taro'
    lastName 'Tanaka'
    address {
      country 'Japan'
      prefecture 'Tokyo'
    }
  }
}

def requestEntity = builder.toString()

あとは、普通にJAX-RS Clientのコードとして書くだけです。

  def response =
    client
    .target("http://localhost:8080/message")
    .request()
    .put(Entity.json(requestEntity))

  def responseEntity = response.readEntity(LinkedHashMap)

  assert responseEntity['message'] == 'こんにちは [Tanaka Taro]!'

サーバー側からは、送信したJSONリクエストのfirstNameとlastNameを合わせたレスポンスが返ってくるものとします。

Java EEAPIですが、まあまあ簡単に書けるのでこれでいいかなぁと思いました。もうちょっとプリミティブにやりたいと思ったら、Async Http Clientを選べばいいような気がします。

なお、JsonBuilderに頼らなくても、普通にMapやListのリテラルでリクエストを作ってもいいと思います。

def requestEntity =
  [
    people: [
      person: [
        firstName: 'Taro',
        lastName: 'Tanaka',
        address: [
          country: 'Japan',
          prefecture: 'Tokyo'
        ]
      ]
    ]
  ]

ところで、サーバー側ですが、こちらもGroovy&JAX-RSで用意しました。
server.groovy

import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import javax.ws.rs.Path
import javax.ws.rs.Produces
import javax.ws.rs.PUT
import javax.ws.rs.core.MediaType

@Grab('org.jboss.resteasy:resteasy-jdk-http:3.0.11.Final')
@Grab('org.jboss.resteasy:resteasy-jackson2-provider:3.0.11.Final')
import org.jboss.resteasy.plugins.server.sun.http.HttpContextBuilder

import com.sun.net.httpserver.HttpServer

@Path("message")
class MessageResource {
  @PUT
  @Produces(MediaType.APPLICATION_JSON)
  def message(Map request) {
    def person = request['people']['person']
    [ message: "こんにちは [${person['lastName']} ${person['firstName']}]!".toString() ]
  }
}

def server = HttpServer.create(new InetSocketAddress(8080), 10)
def contextBuilder = new HttpContextBuilder()

contextBuilder.deployment.actualResourceClasses.add(MessageResource)

def context = contextBuilder.bind(server)

server.start()

println("[${LocalDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss'))}] RestEasyJdkHttpd startup[${server.address}].")

JDKについているHttpServerに、JAX-RSリソースをデプロイしたものです。これで、動作確認も簡単に。