🥰
http4s の最小構成:クライアント:シンプルにリクエストを送る
の続編です.
需要がありそうなら websocket, ストリーミング, 簡易的な jwt 認証や circe のカスタム Codec の使い方なども書くので気になる方はバッジを送ったりしてください💰
http response を文字列で受け取る
Scala CLI の例
req.scala
//> using scala "3.2.1"
//> using lib "org.typelevel::cats-effect::3.4.5"
//> using lib "org.http4s::http4s-core::1.0.0-M38"
//> using lib "org.http4s::http4s-ember-client::1.0.0-M38"
import cats.effect.*
import cats.effect.unsafe.implicits.global
import org.http4s.ember.client.EmberClientBuilder
val program = EmberClientBuilder.default[IO].build.use { client =>
for
// expect[T] の T に取得したいデータ型を指定する.
// ここではレスポンスを文字列で取得するので String を指定する.
res <- client.expect[String]("http://httpbin.org/get")
_ <- IO.println(res)
yield ()
}
@main def run = program.unsafeRunSync()
Tips
EmberClientBuilder.default[IO].build
は Resource[IO,Client]
型を返します.
Resource
は InputStream#close()
のように後始末が必要なデータ型を表現するための型です.
val program = EmberClientBuilder.default[IO].build.use { client =>
Http クライアントは解放時に保持したリソース、例えばコネクションを破棄したりするので Resource
型になります.
SBT の場合
build.sbt
scalaVersion := "3.2.1"
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-effect" % "3.4.5",
"org.http4s" %% "http4s-core" % "1.0.0-M38",
"org.http4s" %% "http4s-ember-client" % "1.0.0-M38",
)
src/main/scala/Main.scala
import cats.effect.*
import org.http4s.ember.client.EmberClientBuilder
object Main extends IOApp:
def run(args: List[String]): IO[ExitCode] =
val program = EmberClientBuilder.default[IO].build.use { client =>
for
res <- client.expect[String]("http://httpbin.org/get")
_ <- IO.println(res)
yield ()
}
program.as(ExitCode.Success)
Http response の json を circe でパースする
req.scala
//> using scala "3.2.1"
//> using lib "org.typelevel::cats-effect::3.4.5"
+//> using lib "io.circe::circe-core:0.15.0-M1"
+//> using lib "io.circe::circe-generic:0.15.0-M1"
//> using lib "org.http4s::http4s-core::1.0.0-M38"
//> using lib "org.http4s::http4s-ember-client::1.0.0-M38"
+//> using lib "org.http4s::http4s-circe::1.0.0-M38"
+import io.circe.*
// asJson などのメソッドを生やすための import
+import io.circe.syntax.*
import cats.effect.*
import cats.effect.unsafe.implicits.global
import org.http4s.ember.client.EmberClientBuilder
+import org.http4s.circe.CirceEntityCodec.circeEntityDecoder
// .{A => A'} は import 時に alias をつけるための文法
+import io.circe.Printer.{spaces2 => Print2Indents}
+case class HttpBinResponse(
+ args: Map[String,String],
+ headers: Headers,
+ origin: String,
+ url: String
+) derives Decoder, Encoder.AsObject
// Decoder は Json => HttpBinResponse への変換を
// Encoder は HttpResponse => Json への変換を行う
+case class Headers(
+ Accept: String,
+ Date: String,
+ Host: String,
// フィールド名に `-` などを含む場合は "`"(バックティック)で
// フィールド名をくくる
+ `User-Agent`: String,
+ `X-Amzn-Trace-Id`: String,
+)
val program = EmberClientBuilder.default[IO].build.use { client =>
for
// expect[T] の T に HttpBinResponse を指定する.
// この T に入れる型は circe の Decoder を derives する必要がある.
// (auto derivation すれば不要だがここでは割愛)
+ res <- client.expect[HttpBinResponse]("http://httpbin.org/get")
+ _ <- IO.println(Print2Indents print res.asJson)
yield ()
}
@main def run = program.unsafeRunSync()
参考
Discussion