0

同期および非同期環境で実装できる基盤として使用するライブラリを構築していSttp.client3ます。サービスには zio-http を使用し、他のサービスと対話するには sttp-client を使用しています。

私には次の特徴があります。

trait CoingeckoApiClient extends CoingeckoClient {

  .....
   override def ping: Either[CoingeckoApiError, PingResponse] =
    get[PingResponse](endpoint = "ping", QueryParams())

  def get[T](endpoint: String, queryParams: QueryParams)(
      using Format[T]
  ): Either[CoingeckoApiError, T]
}

そしてAPI

class CoingeckoApi[F[_], P](using val backend: SttpBackend[F, P]) {
  def get(endpoint: String, params: QueryParams): F[Response[Either[String, String]]] = {
      val apiUrl = s"${CoingeckoApi.baseUrl}/$endpoint"
      basicRequest
        .get(
          uri"$apiUrl"
            .withParams(params)
        )
        .send(backend)
  }
}

同期実装は次のとおりです。

class CoingeckoApiBasic(api: CoingeckoApi[Identity, Any]) extends CoingeckoApiClient {
  def get[T](endpoint: String, queryParams: QueryParams)(using Format[T]): Either[CoingeckoApiError, T] =
    api.get(endpoint, queryParams).body match {
      case Left(json) =>
        Json.parse(json).validate[CoingeckoApiError] match {
          case JsSuccess(value, _) => Left(value)
          case JsError(errors) =>
            Left(CoingeckoApiError.internalApiError(Some("Unknown Api Error")))
        }

      case Right(json) =>
        Json.parse(json).validate[T] match {
          case JsSuccess(value, _) =>
            Right(value)
          case JsError(errors) =>
            Left(
              CoingeckoApiError
                .internalApiError(Some(s"Invalid Response for $endpoint"))
            )
        }
    }
}

だから私はZIOで非同期実装を提供しようとしています

class CoingeckoApiZIO(api: CoingeckoApi[UIO, Any]) extends CoingeckoApiClient {
  def get[T](endpoint: String, queryParams: QueryParams)(using Format[T]): Either[CoingeckoApiError, T] =
  Runtime.unsafeRun {
    api.get(endpoint, queryParams).map(r => r.body match {
      case Left(json) =>
        Json.parse(json).validate[CoingeckoApiError] match {
          case JsSuccess(value, _) => Left(value)
          case JsError(errors) =>
            Left(CoingeckoApiError.internalApiError(Some("Unknown Api Error")))
        }

      case Right(json) =>
        Json.parse(json).validate[T] match {
          case JsSuccess(value, _) =>
            Right(value)
          case JsError(errors) =>
            Left(
              CoingeckoApiError
                .internalApiError(Some(s"Invalid Response for $endpoint"))
            )
        }
    })
  }
}

つまり、このレベルでランタイムを提供する必要があるということですか? ZIO、Future などで使用できるほど柔軟な API を提供するのは少し難しいように思えます。おそらく、ここで重要な何かが欠けています。

class CoingeckoApi[F[_], P]環境をサポートするには、おそらく署名を変更する必要がありますか?

複数のバックエンドを利用できるsttpの手順を踏襲しようとしているのですが、スケーリングが少し難しいか、APIを書き直す必要があるようです。

4

1 に答える 1