Pure Functional Twitch API client on scala
Pure Functional Twitch API client on scala
Twitch API supports two different authentication mechanisms:
For more information refer to: Twitch apps and authentication guide.
First of all you need to define which authentication schema you are going to use. You may authenticate based on Client ID
val clientId: String = "your-client-id"
val env = io.twitchapi4s.ClientIdTwitchEnv(clientId)
or Token
val token: String = "your-twitch-token"
val env = io.twitchapi4s.TokenTwitchEnv(token)
Once environment is created you should create endpoint
with necessary operations, for example,
import scalaz.zio.interop.catz._
import scalaz.zio.interop.catz.mtl._
import io.twitchapi4s.zio.client._
import io.twitchapi4s.zio.client.TwitchEndpoint._
val endpoint = new TwitchEndpoint[TwitchEnv](backend)
with GamesEndpoint[TwitchEnv]
with StreamsEndpoint[TwitchEnv]
with UsersEndpoint[TwitchEnv]
with VideosEndpoint[TwitchEnv]
This snapshot and next examples are based on implementation for ZIO but examples for Monix are completely the same except package name.
Now we are ready to execute some queries:
runtime.unsafeRunSync((for {
topGames <- endpoint.getTopGamesR()
topGame = topGames.data.head
videosByGame <- endpoint.getVideosR(GameVideoId(topGame.id))
video = videosByGame.data.head
userById <- endpoint.getUsersR(ids = List(video.userId), logins = Nil)
followers <- endpoint.getFollowsR(fromId = Some(video.userId), toId = None)
} yield (userById, followers)).provide(env))
This approach works fine but have couple drawbacks:
ClientIdTwitchEnv
) then your rate limit is low and you may getTokenTwitchEnv
) then your token may expire at any time and you have toTo overcome both these issues you may create endpoint
with another environmentio.twitchapi4s.zio.client.RecoverableTwitchState
import scalaz.zio.interop.catz._
import scalaz.zio.interop.catz.mtl._
import io.twitchapi4s.zio.client._
import io.twitchapi4s.zio.client.TwitchEndpoint._
val recoverableEndpoint = new TwitchEndpoint[RecoverableTwitchState](backend)
with GamesEndpoint[RecoverableTwitchState]
Now to load some data from Twitch you should write something like that
val env = WithoutTokenEnv(clientId, clientSecret)
val ref = runtime.unsafeRunSync(Ref.make[RecoverableTwitchEnv](env)).toEither.right.get
runtime.unsafeRunSync((for {
starcraft <- recoverableEndpoint.getGamesS(Nil, List("Starcraft"))
starcraft2 <- recoverableEndpoint.getGamesS(Nil, List("Starcraft 2"))
} yield (starcraft, starcraft2)).provide(RecoverableTwitchState(ref))
This code
scalaz.zio.Ref
with WithoutTokenEnv
which contains Client ID and Client SecretRef
into RecoverableTwitchState
Client ID and Client Secret will be used to generate token before first request to Twitch. If authentication exception is
thrown at some moment then recoverableEndpoint
will try to recreate token again before propagation this exception to outer
code.
You may find more examples for ZIO and Monix in classes io.twitchapi4s.zio.client.TwitchTest
and io.twitchapi4s.monix.client.TwitchTest
.