使用 http4sVersion 依赖项时 HTTP 服务的 TypeLevel Scala 编译错误

问题描述 投票:0回答:1

我正在尝试使用

TypeLevel Scala
编写一个示例 HTTP 服务,该服务会访问 National Weather Service API。我遇到类型不匹配错误并且
EntityEncoder
来自
cats.effect.IO
包导入。

build.sbt

lazy val http4sVersion    = "1.0.0-M37"
lazy val circeVersion     = "0.14.5"
lazy val sttpVersion      = "3.9.0"
lazy val munitVersion     = "0.7.29"
lazy val logbackVersion   = "1.4.7"

ThisBuild / scalaVersion := "2.13.12"

libraryDependencies ++= Seq(
  "org.http4s" %% "http4s-blaze-server" % http4sVersion,
  "org.http4s" %% "http4s-circe"        % http4sVersion,
  "org.http4s" %% "http4s-dsl"          % http4sVersion,
  "io.circe"   %% "circe-generic"       % circeVersion,
  "io.circe"   %% "circe-literal"       % circeVersion,
  "com.softwaremill.sttp.client3" %% "core" % sttpVersion,
  "com.softwaremill.sttp.client3" %% "circe" % sttpVersion,
  "org.typelevel" %% "cats-effect" % "3.5.1",
  "org.scalameta" %% "munit" % munitVersion % Test,
  "ch.qos.logback" % "logback-classic" % logbackVersion
)

WeatherServer.scala

package weather

import cats.effect._
import org.http4s._
import org.http4s.dsl.io._
import org.http4s.implicits._
import org.http4s.blaze.server.BlazeServerBuilder
import org.http4s.circe._
import io.circe.generic.auto._
import sttp.client3._
import sttp.client3.circe._

object WeatherServer extends IOApp {

  case class WeatherResponse(forecast: String, temperatureType: String)

  def classifyTemperature(temp: Double): String = {
    if (temp < 10) "cold"
    else if (temp > 25) "hot"
    else "moderate"
  }

  def getWeather(latitude: Double, longitude: Double): IO[WeatherResponse] = {
    val backend = HttpURLConnectionBackend()
    val request = basicRequest
      .get(uri"https://api.weather.gov/points/$latitude,$longitude")
      .response(asJson[Map[String, Any]])

    IO.fromEither(request.send(backend).body)
      .flatMap { body =>
        val forecastUrl = body("properties").asInstanceOf[Map[String, Any]]("forecast").toString
        val forecastRequest = basicRequest.get(uri"$forecastUrl").response(asJson[Map[String, Any]])
        IO.fromEither(forecastRequest.send(backend).body)
          .map { forecastBody =>
            val forecastData = forecastBody("properties").asInstanceOf[Map[String, Any]]("periods").asInstanceOf[List[Map[String, Any]]]
            val todayForecast = forecastData.head("shortForecast").toString
            val temperature = forecastData.head("temperature").toString.toDouble
            WeatherResponse(todayForecast, classifyTemperature(temperature))
          }
      }
  }

  val weatherService = HttpRoutes.of[IO] {
    case GET -> Root / "weather" :? LatitudeQueryParamMatcher(lat) +& LongitudeQueryParamMatcher(lon) =>
      getWeather(lat, lon).flatMap { weather =>
        Ok(weather)
      }
  }

  val httpApp = weatherService.orNotFound

  def run(args: List[String]): IO[ExitCode] =
    BlazeServerBuilder[IO](runtime.compute)
      .bindHttp(8080, "0.0.0.0")
      .withHttpApp(httpApp)
      .serve
      .compile
      .drain
      .as(ExitCode.Success)
}

object LatitudeQueryParamMatcher extends QueryParamDecoderMatcher[Double]("latitude")
object LongitudeQueryParamMatcher extends QueryParamDecoderMatcher[Double]("longitude")

当我使用

sbt run
运行它时:

[info] welcome to sbt 1.10.2 (Oracle Corporation Java 21)
[info] loading project definition from /Users/pnwlover/weatherservice/project
[info] loading settings for project weatherservice from build.sbt ...
[info] set current project to weatherservice (in build file:/Users/pnwlover/weatherservice/)
[info] compiling 2 Scala sources to /Users/pnwlover/weatherservice/target/scala-2.13/classes ...
[error] /Users/pnwlover/weatherservice/src/main/scala/weather/WeatherServer.scala:26:12: type mismatch;
[error]  found   : StringContext
[error]  required: ?{def uri(x$1: ? >: Double, x$2: ? >: Double): ?}
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error]  both method http4sLiteralsSyntax in trait LiteralsSyntax of type (sc: StringContext): org.http4s.syntax.LiteralsOps
[error]  and method UriContext in trait UriInterpolator of type (sc: StringContext): sttp.client3.package.UriContext
[error]  are possible conversion functions from StringContext to ?{def uri(x$1: ? >: Double, x$2: ? >: Double): ?}
[error]       .get(uri"https://api.weather.gov/points/$latitude,$longitude")
[error]            ^
[error] /Users/pnwlover/weatherservice/src/main/scala/weather/WeatherServer.scala:27:23: could not find implicit value for evidence parameter of type io.circe.Decoder[Map[String,Any]]
[error]       .response(asJson[Map[String, Any]])
[error]                       ^
[error] /Users/pnwlover/weatherservice/src/main/scala/weather/WeatherServer.scala:46:11: Cannot convert from weather.WeatherServer.WeatherResponse to an Entity, because no EntityEncoder[cats.effect.IO, weather.WeatherServer.WeatherResponse] instance could be found.
[error]         Ok(weather)
[error]           ^
[error] three errors found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 2 s, completed Sep 25, 2024, 3:00:05PM

scala scala-cats circe http4s
1个回答
0
投票

build.sbt
文件进行以下更改即可使其正常工作:

lazy val http4sVersion = "0.23.28"
lazy val circeVersion = "0.14.5"
lazy val sttpVersion = "3.8.3"

ThisBuild / scalaVersion := "2.13.14"

libraryDependencies ++= Seq(
  "org.http4s" %% "http4s-ember-server" % http4sVersion,
  "org.http4s" %% "http4s-circe" % http4sVersion,
  "org.http4s" %% "http4s-dsl" % http4sVersion,
  "io.circe" %% "circe-generic" % circeVersion,
  "io.circe" %% "circe-parser" % circeVersion,
  "com.softwaremill.sttp.client3" %% "core" % sttpVersion,
  "com.softwaremill.sttp.client3" %% "circe" % sttpVersion,
  "com.comcast" %% "ip4s-core" % "3.0.1",
  "org.typelevel" %% "log4cats-slf4j" % "2.6.0",
  "ch.qos.logback" % "logback-classic" % "1.4.7",
  
  // Test dependencies
  "org.scalatest" %% "scalatest" % "3.2.15" % Test,
  "org.typelevel" %% "cats-effect-testing-scalatest" % "1.5.0" % Test,
  "org.http4s" %% "http4s-client" % http4sVersion % Test
)

Compile / run / fork := true

// Add this line to enable parallel execution of tests
Test / parallelExecution := true
© www.soinside.com 2019 - 2024. All rights reserved.