最近、簡単にスクリプト的な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 EEのAPIですが、まあまあ簡単に書けるのでこれでいいかなぁと思いました。もうちょっとプリミティブにやりたいと思ったら、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}].")