Skip to content

Commit e92ce91

Browse files
committed
wip
1 parent f263d4a commit e92ce91

15 files changed

+91
-106
lines changed

README.md

+26-30
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ To get started check the documentation on [https://pokeapi.co/docs/v2](https://p
1212
Add the following to your build.sbt:
1313

1414
```scala
15-
libraryDependencies += "io.github.juliano" % "pokeapi-scala_3" % "0.3.0"
15+
libraryDependencies += "io.github.juliano" % "pokeapi-scala_3" % "0.4.0"
1616
```
1717

1818
### `Sttp` backends support
@@ -21,7 +21,7 @@ This client is written using [sttp](https://sttp.softwaremill.com/en/latest/inde
2121

2222
## Usage
2323

24-
Instantiate a backend implicitly, create a `PokeApiClient()` and start consuming the api, calling `client.send(PokeRequest(id | name))`. Most requests accept an `id: Long` or `name: String` (have a look at [Scala 3 Union Types](https://docs.scala-lang.org/scala3/book/types-union.html)).
24+
Instantiate a backend, use it create a `PokeApiClient(backend)` and start consuming the api, calling `client.send(PokeRequest(id | name))`. Most requests accept an `id: Long` or `name: String` (have a look at [Scala 3 Union Types](https://docs.scala-lang.org/scala3/book/types-union.html)).
2525

2626
It's possible to [list / paginate resources](https://pokeapi.co/docs/v2#resource-listspagination-section) as well, calling `client.send(PokeRequest.resourceList(offset: Int, limit: Int))`
2727

@@ -35,43 +35,23 @@ Every response is automatically cached in memory, making all subsequent requests
3535

3636
```scala
3737
import io.github.juliano.pokeapi.requests.BerryRequest
38-
import sttp.client3.{ HttpClientSyncBackend, Identity, SttpBackend }
38+
import sttp.client4.httpclient.HttpClientSyncBackend
3939

40-
given backend: SttpBackend[Identity, Any] = HttpClientSyncBackend()
41-
val client = PokeApiClient()
40+
val client = PokeApiClient(HttpClientSyncBackend())
4241

4342
val berry = client.send(BerryRequest(1))
4443
println(berry.name)
4544
```
4645

47-
### Try
48-
49-
```scala
50-
import io.github.juliano.pokeapi.requests.MoveRequest
51-
import sttp.client3.{ SttpBackend, TryHttpURLConnectionBackend }
52-
import scala.util.*
53-
54-
given backend: SttpBackend[Try, Any] = TryHttpURLConnectionBackend()
55-
val client = PokeApiClient()
56-
57-
client.send(MoveRequest("pound")) match {
58-
case Success(move) => println(move.names)
59-
case Failure(t) => println(s"Failed with: $t")
60-
}
61-
```
62-
6346
### Future
6447

6548
```scala
6649
import io.github.juliano.pokeapi.requests.ContestTypeRequest
67-
import sttp.capabilities.WebSockets
68-
import sttp.client3.{ HttpClientFutureBackend, SttpBackend }
50+
import sttp.client4.httpclient.HttpClientFutureBackend
6951
import scala.concurrent.ExecutionContext.Implicits.global
70-
import scala.concurrent.Future
7152
import scala.util.*
7253

73-
given backend: SttpBackend[Future, WebSockets] = HttpClientFutureBackend()
74-
val client = PokeApiClient()
54+
val client = PokeApiClient(HttpClientFutureBackend())
7555

7656
client.send(ContestTypeRequest(1)).onComplete {
7757
case Success(contest) => println(contest.names)
@@ -83,10 +63,10 @@ client.send(ContestTypeRequest(1)).onComplete {
8363

8464
```scala
8565
import io.github.juliano.pokeapi.requests.PokemonRequest
86-
import sttp.client3.asynchttpclient.zio.AsyncHttpClientZioBackend
66+
import sttp.client4.asynchttpclient.zio.AsyncHttpClientZioBackend
8767
import zio.{ Runtime, Unsafe, ZIO }
8868

89-
val client = AsyncHttpClientZioBackend().map(implicit backend => PokeApiClient())
69+
val client = AsyncHttpClientZioBackend().map(implicit backend => PokeApiClient(backend))
9070

9171
val zio = client.flatMap(_.send(PokemonRequest("bulbasaur")))
9272
val pokemon = Unsafe.unsafeCompat { implicit u =>
@@ -101,14 +81,30 @@ print(pokemon.id)
10181
import cats.effect.IO
10282
import cats.effect.unsafe.implicits.global
10383
import io.github.juliano.pokeapi.requests.LocationRequest
104-
import sttp.client3.asynchttpclient.cats.AsyncHttpClientCatsBackend
84+
import sttp.client4.asynchttpclient.cats.AsyncHttpClientCatsBackend
10585

106-
val client = AsyncHttpClientCatsBackend[IO]().map(implicit backend => PokeApiClient())
86+
val client = AsyncHttpClientCatsBackend[IO]().map(implicit backend => PokeApiClient(backend))
10787

10888
val list = client.flatMap(_.send(LocationRequest.resourceList())).unsafeRunSync()
10989
print(list.count)
11090
```
11191

92+
### Pekko
93+
94+
```scala
95+
import io.github.juliano.pokeapi.requests.MoveRequest
96+
import scala.concurrent.ExecutionContext.Implicits.global
97+
import scala.util.*
98+
import sttp.client4.pekkohttp.PekkoHttpBackend
99+
100+
val client = PokeApiClient(PekkoHttpBackend())
101+
102+
client.send(MoveRequest("pound")).onComplete {
103+
case Success(move) => println(move.names)
104+
case Failure(t) => println(s"Failed with: $t")
105+
}
106+
```
107+
112108
You can find more examples using Fs2, Armaria and okhttp [in the tests](https://github.com/juliano/pokeapi-scala/tree/main/src/test/scala/io/github/juliano/pokeapi)
113109

114110
## Contributing

build.sbt

+13-11
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,21 @@ lazy val pokeapi = project
2222
scalafmtOnCompile := true,
2323
scalacOptions := Seq("-Xmax-inlines", "64"),
2424
libraryDependencies ++= Seq(
25-
"com.softwaremill.sttp.client3" %% "core" % "3.9.3",
26-
"com.softwaremill.sttp.client3" %% "zio-json" % "3.9.3",
25+
"com.softwaremill.sttp.client4" %% "core" % "4.0.0-M9",
26+
"com.softwaremill.sttp.client4" %% "zio-json" % "4.0.0-M9",
2727
"com.github.blemale" %% "scaffeine" % "5.2.1",
2828
"org.scalameta" %% "munit" % "1.0.0-M11" % Test,
29-
"com.softwaremill.sttp.client3" %% "armeria-backend-cats" % "3.9.3" % Test,
30-
"com.softwaremill.sttp.client3" %% "async-http-client-backend-cats" % "3.9.3" % Test,
31-
"com.softwaremill.sttp.client3" %% "fs2" % "3.9.3" % Test,
32-
"com.softwaremill.sttp.client3" %% "async-http-client-backend-fs2" % "3.9.3" % Test,
33-
"com.softwaremill.sttp.client3" %% "zio" % "3.9.3" % Test,
34-
"com.softwaremill.sttp.client3" %% "async-http-client-backend-zio" % "3.9.3" % Test,
35-
"com.softwaremill.sttp.client3" %% "armeria-backend-zio" % "3.9.3" % Test,
36-
"com.softwaremill.sttp.client3" %% "armeria-backend" % "3.9.3" % Test,
37-
"com.softwaremill.sttp.client3" %% "okhttp-backend" % "3.9.3" % Test
29+
"com.softwaremill.sttp.client4" %% "armeria-backend-cats" % "4.0.0-M9" % Test,
30+
"com.softwaremill.sttp.client4" %% "async-http-client-backend-cats" % "4.0.0-M9" % Test,
31+
"com.softwaremill.sttp.client4" %% "fs2" % "4.0.0-M9" % Test,
32+
"com.softwaremill.sttp.client4" %% "async-http-client-backend-fs2" % "4.0.0-M9" % Test,
33+
"com.softwaremill.sttp.client4" %% "zio" % "4.0.0-M9" % Test,
34+
"com.softwaremill.sttp.client4" %% "async-http-client-backend-zio" % "4.0.0-M9" % Test,
35+
"com.softwaremill.sttp.client4" %% "armeria-backend-zio" % "4.0.0-M9" % Test,
36+
"com.softwaremill.sttp.client4" %% "armeria-backend" % "4.0.0-M9" % Test,
37+
"com.softwaremill.sttp.client4" %% "okhttp-backend" % "4.0.0-M9" % Test,
38+
"com.softwaremill.sttp.client4" %% "pekko-http-backend" % "4.0.0-M9" % Test,
39+
"org.apache.pekko" %% "pekko-stream" % "1.0.2" % Test
3840
),
3941
excludeDependencies ++= Seq(
4042
"org.scala-lang.modules" % "scala-collection-compat_2.13"

src/main/scala/io/github/juliano/pokeapi/PokeApiClient.scala

+7-9
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,17 @@ package io.github.juliano.pokeapi
22

33
import com.github.blemale.scaffeine.{ Cache, Scaffeine }
44
import io.github.juliano.pokeapi.PokeApiClient.*
5-
import sttp.client3.*
6-
import sttp.client3.ziojson.asJson
5+
import sttp.client4.*
6+
import sttp.client4.ziojson.asJson
77
import sttp.model.{ MediaType, Uri }
88
import sttp.monad.MonadError
99
import sttp.monad.syntax.MonadErrorOps
1010
import zio.json.JsonDecoder
1111

1212
import scala.concurrent.duration.DurationInt
1313

14-
case class PokeApiClient[F[_], +P](host: ApiHost = ApiHost.default)(using
15-
backend: SttpBackend[F, P]
16-
):
17-
given monadError: MonadError[F] = backend.responseMonad
14+
case class PokeApiClient[F[_]](backend: Backend[F], host: ApiHost = ApiHost.default):
15+
given monadError: MonadError[F] = backend.monad
1816
private val cache: Cache[String, Product] = Scaffeine().build[String, Product]()
1917

2018
def send[A](request: PokeRequest[A])(using JsonDecoder[A]): F[A] =
@@ -25,8 +23,8 @@ case class PokeApiClient[F[_], +P](host: ApiHost = ApiHost.default)(using
2523
doSend(request).flatMap {
2624
case Right(value) =>
2725
cache.put(request.toString, value.asInstanceOf[Product])
28-
monadError.unit(value)
29-
case Left(error) => monadError.error(error)
26+
monadError.unit(value.asInstanceOf[A])
27+
case Left(error) => monadError.error(new Exception(error.toString))
3028
}
3129

3230
private def doSend[A](
@@ -39,7 +37,7 @@ case class PokeApiClient[F[_], +P](host: ApiHost = ApiHost.default)(using
3937

4038
object PokeApiClient:
4139
type FailureResponse = ResponseException[String, String]
42-
type SttpRequest[A] = Request[Either[FailureResponse, A], Any]
40+
type SttpRequest[A] = Request[Either[FailureResponse, A]]
4341

4442
trait PokeRequest[A](id: String | Long):
4543
val resource: String

src/test/scala/io/github/juliano/pokeapi/BerriesSuite.scala

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package io.github.juliano.pokeapi
22

33
import io.github.juliano.pokeapi.requests.*
4-
import sttp.client3.{ HttpClientSyncBackend, Identity, SttpBackend }
4+
import sttp.client4.httpclient.HttpClientSyncBackend
55

66
class BerriesSuite extends munit.FunSuite:
7-
given backend: SttpBackend[Identity, Any] = HttpClientSyncBackend()
8-
val client = PokeApiClient()
7+
val client = PokeApiClient(HttpClientSyncBackend())
98

109
test("berry by id") {
1110
val berry = client.send(BerryRequest(1))

src/test/scala/io/github/juliano/pokeapi/ContestsSuite.scala

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
package io.github.juliano.pokeapi
22

33
import io.github.juliano.pokeapi.requests.*
4-
import sttp.capabilities.WebSockets
5-
import sttp.client3.{ HttpClientFutureBackend, SttpBackend }
6-
7-
import scala.concurrent.Future
4+
import sttp.client4.httpclient.HttpClientFutureBackend
85

96
class ContestsSuite extends FutureSuite:
10-
given backend: SttpBackend[Future, WebSockets] = HttpClientFutureBackend()
11-
val client = PokeApiClient()
7+
val client = PokeApiClient(HttpClientFutureBackend())
128

139
spec("contest type by id", ContestTypeRequest(1), _.name == "cool")
1410
spec("contest type by name", ContestTypeRequest("cool"), _.id == 1)

src/test/scala/io/github/juliano/pokeapi/EncountersSuite.scala

+2-4
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ package io.github.juliano.pokeapi
33
import cats.effect.IO
44
import cats.effect.unsafe.implicits.global
55
import io.github.juliano.pokeapi.requests.*
6-
import sttp.client3.SttpBackend
7-
import sttp.client3.armeria.cats.ArmeriaCatsBackend
6+
import sttp.client4.armeria.cats.ArmeriaCatsBackend
87

98
class EncountersSuite extends munit.FunSuite:
10-
given backend: SttpBackend[IO, Any] = ArmeriaCatsBackend[IO]()
11-
val client: PokeApiClient[IO, Any] = PokeApiClient()
9+
val client: PokeApiClient[IO] = PokeApiClient(ArmeriaCatsBackend[IO]())
1210

1311
test("enconter method by id") {
1412
val encounterMethod = client.send(EncounterMethodRequest(1)).unsafeRunSync()

src/test/scala/io/github/juliano/pokeapi/EvolutionSuite.scala

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ package io.github.juliano.pokeapi
22

33
import cats.effect.IO
44
import io.github.juliano.pokeapi.requests.{ EvolutionChainRequest, EvolutionTriggerRequest }
5-
import sttp.client3.asynchttpclient.fs2.AsyncHttpClientFs2Backend
5+
import sttp.client4.asynchttpclient.fs2.AsyncHttpClientFs2Backend
66

77
class EvolutionSuite extends Fs2Suite:
8-
val client = AsyncHttpClientFs2Backend.resource[IO]().map(implicit backend => PokeApiClient())
8+
val client =
9+
AsyncHttpClientFs2Backend.resource[IO]().map(implicit backend => PokeApiClient(backend))
910

1011
spec("evolution chain by id", EvolutionChainRequest(1), _.babyTriggerItem.isEmpty)
1112
spec("evolution chain resource list", EvolutionChainRequest.resourceList(), _.count == 541)

src/test/scala/io/github/juliano/pokeapi/GamesSuite.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ package io.github.juliano.pokeapi
22

33
import cats.effect.IO
44
import io.github.juliano.pokeapi.requests.*
5-
import sttp.client3.httpclient.fs2.HttpClientFs2Backend
5+
import sttp.client4.httpclient.fs2.HttpClientFs2Backend
66

77
class GamesSuite extends Fs2Suite:
8-
val client = HttpClientFs2Backend.resource[IO]().map(implicit backend => PokeApiClient())
8+
val client = HttpClientFs2Backend.resource[IO]().map(implicit backend => PokeApiClient(backend))
99

1010
spec("generation by id", GenerationRequest(1), _.name == "generation-i")
1111
spec("generation by name", GenerationRequest("generation-i"), _.id == 1)

src/test/scala/io/github/juliano/pokeapi/ItemsSuite.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package io.github.juliano.pokeapi;
22

33
import io.github.juliano.pokeapi.requests.*
4-
import sttp.client3.httpclient.zio.HttpClientZioBackend
4+
import sttp.client4.httpclient.zio.HttpClientZioBackend
55

66
class ItemsSuite extends ZIOSuite:
7-
val client = HttpClientZioBackend().map(implicit backend => PokeApiClient())
7+
val client = HttpClientZioBackend().map(implicit backend => PokeApiClient(backend))
88

99
spec("item by id", ItemRequest(1), _.name == "master-ball")
1010
spec("item by name", ItemRequest("master-ball"), _.id == 1)

src/test/scala/io/github/juliano/pokeapi/LocationsSuite.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ package io.github.juliano.pokeapi
22

33
import cats.effect.IO
44
import io.github.juliano.pokeapi.requests.*
5-
import sttp.client3.asynchttpclient.cats.AsyncHttpClientCatsBackend
5+
import sttp.client4.asynchttpclient.cats.AsyncHttpClientCatsBackend
66

77
class LocationsSuite extends CatsSuite:
8-
val client = AsyncHttpClientCatsBackend[IO]().map(implicit backend => PokeApiClient())
8+
val client = AsyncHttpClientCatsBackend[IO]().map(implicit backend => PokeApiClient(backend))
99

1010
spec("location by id", LocationRequest(1), _.name == "canalave-city")
1111
spec("location by name", LocationRequest("canalave-city"), _.id == 1)

src/test/scala/io/github/juliano/pokeapi/MachinesSuite.scala

+2-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ package io.github.juliano.pokeapi
22

33
import io.github.juliano.pokeapi.requests.MachineRequest
44
import sttp.capabilities.WebSockets
5-
import sttp.client3.{ Identity, SttpBackend }
6-
import sttp.client3.okhttp.OkHttpSyncBackend
5+
import sttp.client4.okhttp.OkHttpSyncBackend
76

87
class MachinesSuite extends munit.FunSuite:
9-
given backend: SttpBackend[Identity, WebSockets] = OkHttpSyncBackend()
10-
val client = PokeApiClient()
8+
val client = PokeApiClient(OkHttpSyncBackend())
119

1210
test("machine by id") {
1311
val machine = client.send(MachineRequest(1))

src/test/scala/io/github/juliano/pokeapi/MovesSuite.scala

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
package io.github.juliano.pokeapi
22

33
import io.github.juliano.pokeapi.requests.*
4-
import sttp.client3.{ SttpBackend, TryHttpURLConnectionBackend }
4+
import sttp.client4.pekkohttp.PekkoHttpBackend
55

6-
import scala.util.Try
7-
8-
class MovesSuite extends TrySuite:
9-
given backend: SttpBackend[Try, Any] = TryHttpURLConnectionBackend()
10-
val client = PokeApiClient()
6+
class MovesSuite extends FutureSuite:
7+
val client = PokeApiClient(PekkoHttpBackend())
118

129
spec("move by id", MoveRequest(1), _.name == "pound")
1310
spec("move by name", MoveRequest("pound"), _.id == 1)

src/test/scala/io/github/juliano/pokeapi/PokemonSuite.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package io.github.juliano.pokeapi
22

33
import io.github.juliano.pokeapi.requests.*
4-
import sttp.client3.asynchttpclient.zio.AsyncHttpClientZioBackend
4+
import sttp.client4.asynchttpclient.zio.AsyncHttpClientZioBackend
55

66
class PokemonSuite extends ZIOSuite:
7-
val client = AsyncHttpClientZioBackend().map(implicit backend => PokeApiClient())
7+
val client = AsyncHttpClientZioBackend().map(implicit backend => PokeApiClient(backend))
88

99
spec("ability by id", AbilityRequest(1), _.name == "stench")
1010
spec("ability by name", AbilityRequest("stench"), _.id == 1)

src/test/scala/io/github/juliano/pokeapi/UtilitySuite.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package io.github.juliano.pokeapi
22

33
import io.github.juliano.pokeapi.requests.LanguageRequest
4-
import sttp.client3.armeria.zio.ArmeriaZioBackend
4+
import sttp.client4.armeria.zio.ArmeriaZioBackend
55

66
class UtilitySuite extends ZIOSuite:
7-
val client = ArmeriaZioBackend().map(implicit backend => PokeApiClient())
7+
val client = ArmeriaZioBackend().map(implicit backend => PokeApiClient(backend))
88

99
spec("language by id", LanguageRequest(1), _.name == "ja-Hrkt")
1010
spec("language by name", LanguageRequest("ja-Hrkt"), _.id == 1)

0 commit comments

Comments
 (0)