Response の処理 

Request 値が構築できたら、次に HttpClient に渡して、 rundownloadprocessFull, runStream といったメソッドを使って実行することができる。

http.run(r, f) 

HttpClient には多くのメソッドが定義されているが、おそらく最も便利なのは http.run(r, f) メソッドだ。基本的な概念のページで見たようにこれは、 Request 値と FullResponse => A の関数を受け取る。

Gigahorse は、Future[String] を返すために Gigahorse.asString という関数を提供するが、 これを拡張して他の型に応用できることは想像に難くない。

一つ注意するべきなのは、run メソッドは HTTP 2XX 番台のステータスのみを受け付け、 その他の場合は Future を失敗させるということだ。(デフォルトの設定では、3XX のリダイレクトは自動的に処理される)

Future の後処理 

関数を渡すのに加え、中の値を map することで簡単に Future を後付けで処理することができる。

scala> import gigahorse._, support.asynchttpclient.Gigahorse
import gigahorse._
import support.asynchttpclient.Gigahorse

scala> import scala.concurrent._, duration._
import scala.concurrent._
import duration._

scala> import ExecutionContext.Implicits._
import ExecutionContext.Implicits._

scala> Gigahorse.withHttp(Gigahorse.config) { http =>
         val r = Gigahorse.url("http://api.duckduckgo.com").get.
           addQueryString(
             "q" -> "1 + 1",
             "format" -> "json"
           )
         val f0: Future[FullResponse] = http.run(r, identity)
         val f: Future[String] = f0 map { Gigahorse.asString andThen (_.take(60)) }
         Await.result(f, 120.seconds)
       }
res0: String = {"DefinitionSource":"","Heading":"1+1","ImageWidth":0,"Relat

Future に対して何らかの演算を行うときは、implicit な実行コンテキストが必要となる。 実行コンテキストは、Future のコールバックがどのスレッドプールで実行されるかを宣言するものだ。

便宜上、Request のみを受け取る run のオーバーロードもある。

FullResponse を Either に持ち上げる 

Future が失敗する場合があるときによく行われる処理として、内部の AEither[Throwable, A] に持ち上げるということが行われる。

http://getstatuscode.com/ という便利なウェブサイトがあって、これは 任意の HTTP ステータスを返すことができる。失敗した Future に対してブロックするとどうなるかをみてみよう。

scala> Gigahorse.withHttp(Gigahorse.config) { http =>
         val r = Gigahorse.url("http://getstatuscode.com/500")
         val f = http.run(r, Gigahorse.asString)
         Await.result(f, 120.seconds)
       }
gigahorse.StatusError: Unexpected status: 500
  at gigahorse.StatusError$.apply(StatusError.scala:29)
  at gigahorse.support.asynchttpclient.OkHandler$class.onStatusReceived(OkHandler.scala:27)
  at gigahorse.support.asynchttpclient.OkHandler$FullOkHandler.onStatusReceived(OkHandler.scala:32)
  at gigahorse.support.asynchttpclient.AhcHttpClient$$anon$2.onStatusReceived(AhcHttpClient.scala:78)
  at gigahorse.shaded.ahc.org.asynchttpclient.netty.handler.HttpHandler.exitAfterHandlingStatus(HttpHandler.java:89)
  at gigahorse.shaded.ahc.org.asynchttpclient.netty.handler.HttpHandler.notifyHandler(HttpHandler.java:75)
  at gigahorse.shaded.ahc.org.asynchttpclient.netty.handler.HttpHandler.handleHttpResponse(HttpHandler.java:131)
  at gigahorse.shaded.ahc.org.asynchttpclient.netty.handler.HttpHandler.handleRead(HttpHandler.java:184)
  at gigahorse.shaded.ahc.org.asynchttpclient.netty.handler.AsyncHttpClientHandler.channelRead(AsyncHttpClientHandler.java:76)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:356)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:342)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:335)
  at gigahorse.shaded.ahc.io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:356)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:342)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:335)
  at gigahorse.shaded.ahc.io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:356)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:342)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:335)
  at gigahorse.shaded.ahc.io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
  at gigahorse.shaded.ahc.io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
  at gigahorse.shaded.ahc.io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:280)
  at gigahorse.shaded.ahc.io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:396)
  at gigahorse.shaded.ahc.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248)
  at gigahorse.shaded.ahc.io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:356)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:342)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:335)
  at gigahorse.shaded.ahc.io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1294)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:356)
  at gigahorse.shaded.ahc.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:342)
  at gigahorse.shaded.ahc.io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:911)
  at gigahorse.shaded.ahc.io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
  at gigahorse.shaded.ahc.io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:625)
  at gigahorse.shaded.ahc.io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:560)
  at gigahorse.shaded.ahc.io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:477)
  at gigahorse.shaded.ahc.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:439)
  at gigahorse.shaded.ahc.io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:131)
  at gigahorse.shaded.ahc.io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
  at java.lang.Thread.run(Thread.java:745)

Gigahorse.asEither という機構を使って AEither[Throwable, A] に持ち上げることができる。

scala> Gigahorse.withHttp(Gigahorse.config) { http =>
         val r = Gigahorse.url("http://getstatuscode.com/500")
         val f = http.run(r, Gigahorse.asEither)
         Await.result(f, 120.seconds)
       }
res2: Either[Throwable,gigahorse.FullResponse] = Left(gigahorse.StatusError: Unexpected status: 500)

asEither は右バイアスのかかった Either として map することもできる。

scala> Gigahorse.withHttp(Gigahorse.config) { http =>
         val r = Gigahorse.url("http://getstatuscode.com/200")
         val f = http.run(r, Gigahorse.asEither map {
           Gigahorse.asString andThen (_.take(60)) })
         Await.result(f, 120.seconds)
       }
res3: Either[Throwable,String] =
Right(<!DOCTYPE html>
<html lang="en">
    <head>
        <meta ch)

http.processFull(r, f) 

non-2XX レスポンスでエラーを投げたくなくて、例えば 500 レスポンスのボディーテキストを 読み込みたい場合は processFull メソッドを使う。

scala> Gigahorse.withHttp(Gigahorse.config) { http =>
         val r = Gigahorse.url("http://getstatuscode.com/500")
         val f = http.processFull(r, Gigahorse.asString andThen (_.take(60)))
         Await.result(f, 120.seconds)
       }
res4: String =
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta ch