今回はzio-http
のクライアントについて見ていきます。
前章で作成したAPIを利用しつつ、確認していきます。
GETメソッドの場合とPOSTメソッドの場合の二例を具体的に見ていきますが、まず最初にGETメソッドの場合です。
GETメソッド
実処理部分に対して追加と修正を行います。
trait ApplicationService {
(中略)
def getApi: ZIO[Any, Throwable, Response]
}
object ApplicationService {
(中略)
def getApi: ZIO[ApplicationService, Throwable, Response] = {
ZIO.serviceWithZIO[ApplicationService](_.getApi)
}
}
case class ApplicationServiceImpl(client: Client) extends ApplicationService {
(中略)
override def getApi: ZIO[Any, Throwable, Response] = for{
uri <- ZIO.fromEither(URL.decode("http://localhost:8080/text"))
res <- client.request(
Request
.default(
Method.GET,
uri,
Body.empty
)
)
data <- res.body.asString
} yield Response.text(s"http://localhost:8080/text:$data")
}
object ApplicationServiceImpl {
val layer: ZLayer[Client, Nothing, ApplicationService] =
ZLayer{for {
client <- ZIO.service[Client]
} yield ApplicationServiceImpl(client)}
}
この実処理を呼び出すパスを追加します。
object TestController {
def apply(): Http[ApplicationService, Throwable, Request, Response] = Http.collectZIO[Request] {
(中略)
case Method.GET -> Root / "getApi" => ApplicationService.getApi
}
}
最後にHTTPクライアントをDIします。
object MainApp extends ZIOAppDefault {
(中略)
.provide(
Server.default,
ApplicationServiceImpl.layer,
Client.default
)
}
上記を実行し、http://localhost:8080/getApi
にアクセスすると以下の出力を得られます。
http://localhost:8080/text:Hello World!
これは実際にHTTPリクエストを行い、得られた値を表示しています。
コードの内容について詳しく見ていきます。
HTTPクライアントのDI
まず最初にHTTPリクエストを行うに当たってクライアントを準備する必要があります。
そして、準備したクライアントを以下の部分でDIしています。
object MainApp extends ZIOAppDefault {
(中略)
.provide(
Server.default,
ApplicationServiceImpl.layer,
Client.default
)
}
今回HTTPクライアントに対して特別な設定を行う必要がないため、最も基本的なClient.default
を使っていますが、プロキシなどの設定を行うことも可能です。
このDIのため、ApplicationService
,ApplicationServiceImpl
に対しても修正を行っています。
GETリクエスト
リクエストを行うためにまず文字列のURLをURL型に変換します。
URL.decode
関数の返り値の型がEither型であるため、ZIO.fromEither
関数でZIO型に変換しています。
エラー発生時を考え、ZIO型に直しています。
uri <- ZIO.fromEither(URL.decode("http://localhost:8080/text"))
そして、変換したURLを使い、実際のリクエストを行います。
res <- client.request(
Request
.default(
Method.GET,
uri,
Body.empty
)
)
後にも説明しますが、例えばMethod.GET
の部分をMethod.POST
に変えることでPOSTリクエストを行うことが出来たりと、リクエストの条件を変えることもできます。
最後に以下の部分でHTTPレスポンスのボディを取得しています。
data <- res.body.asString
他にもres.status.text
によりレスポンスステータスコードを取得するといったことが出来ます。
POSTメソッド
次にPOSTメソッドについて見ていきます。
最初に実処理部分に対して追記を行います。
trait ApplicationService {
(中略)
def postApi(param:String): ZIO[Any, Throwable, Response]
}
object ApplicationService {
(中略)
def postApi(param:String): ZIO[ApplicationService, Throwable, Response] = {
ZIO.serviceWithZIO[ApplicationService](_.postApi(param))
}
}
case class ApplicationServiceImpl(client: Client) extends ApplicationService {
(中略)
override def postApi(param:String): ZIO[Any, Throwable, Response] = for{
uri <- ZIO.fromEither(URL.decode("http://localhost:8080/postTest"))
res <- client.request(
Request
.default(
Method.POST,
uri,
Body.fromString(
s"userName=$param"
)
)
)
data <- res.body.asString
} yield Response.text(s"http://localhost:8080/postTest:$data").setHeaders(Headers("Content-Type", "text/plain;charset=UTF-8")) // 文字化け対策をしています
}
パスを追加します。
object TestController {
def apply(): Http[ApplicationService, Throwable, Request, Response] = Http.collectZIO[Request] {
(中略)
case Method.GET -> Root / "postApi" / test => ApplicationService.postApi(test)
}
}
上記の修正を行った後実行し、http://localhost:8080/postApi/test
にアクセスると以下の出力を得られます。
http://localhost:8080/postTest:あなたの名前はtestです。
http://localhost:8080/postApi/test
の末尾のtest
の部分を変えると出力も変わるので確認してみてください。
POSTパラメータ
基本的にPOSTリクエストの場合もGETリクエストと変わりません。
POSTパラメータの渡し方の一例として今回は以下の部分で渡しています。
Body.fromString(
s"userName=$param"
)
この場合パラメータ名「userName」に対して変数paramの値を渡しています。
&
で区切ることにより複数のパラメータを渡すこともできます。
終わりに
GETリクエスト、POSTリクエストの方法を今回見てきました。
次章ではzio-http
の中のMiddleware機能について見ていきます。
文字化け対策として.setHeaders(Headers("Content-Type", "text/plain;charset=UTF-8"))
を付加しているResponseがいくつかありますが、このMiddlewareを使い、これを付けなくとも文字化けを起こさないように修正していきたいと思います。
前章:zio-http
次章:Middlewareについて
演習
- 今回のGETメソッド例について実際に動かして挙動を確かめてください。
- 今回のPOSTメソッド例について実際に動かして挙動を確かめてください。