How To Create Simple API Client with ZIO and Http4s

How To Create Simple API Client with ZIO and Http4s

hackernoon.com hackernoon.com1 year ago in#Dev Love55

@juliano-alvesJuliano Alves Open-source enthusiast, a firm believer that future belongs to polyglot and functional programming Discussing with a brazilian friend about the situation in our country, we realised how difficult it is to find information about public spending, and when available, how difficult it can be to reason about it. Joining our forces, we decided to explore some data exposed by the Brazilian government, aiming to provide an easier way to visualise and understand how the public resources has been used. The starting point would be: finding some data to analyse, that is relatively easy (at least from a developer’s perspective) to collect. A good candidate is the Portal da Transparência (in literal translation, Transparency Portal), an initiative to make public data available via APIs or downloading CSV files. Is there a better way to learn about an API than writing a client for it? So let’s do it with ZIO http4s client! Why ZIO? After my talk in Scala UA, someone asked me what has called my attention in the Scala ecosystem recently. I believe ZIO can be a game changer, because it is not “just for functional programmers”. Even though it is strongly based in functional principles, it doesn’t assume the users already understand functional concepts (this is just a Monad!), which can be scary for new joiners. Among all the powerful features ZIO provides, it’s designed to be easy to use and adopt, what is from my perspective, by far, its best feature. #ScalaThankYou ZIO Team! The HttpClient module The API supports only GET requests, what makes the trait definition very simple: package pdt.http import io.circe.Decoder import org.http4s.client.Client import zio._ object HttpClient { type HttpClient = Has[Service] trait Service { protected val rootUrl = “http://www.transparencia.gov.br/api-de-dados/” def get[T](uri: String, parameters: Map[String, String]) (implicit d: Decoder[T]): Task[T] } def http4s: ZLayer[Has[Client[Task]], Nothing, HttpClient] = ??? } Service has only one method get[T] with arguments resource: String and parameters: Map[String, String] , which will become part of the url in the format “resource?key=value” . It takes an implicit io.circe.Decoder[T] as well, used to decode the json result into T . type HttpClient = Has[Service] In simple terms, Has allows us to use our Service as a dependency. The next line makes it easier to understand: def http4s: ZLayer[Has[Client[Task]], Nothing, HttpClient] = ??? The http4s method will create a ZLayer , which is very similar to ZIO data type ; it requires a Has[Client[Task]] to be built, won’t produce any errors (that’s what that Nothing means) and will return an implementation of our Service : HttpClient , the one we defined using Has . We should use type aliases to make ZLayer more expressive as well. Knowing our layer can’t fail, we can use URLayer : def http4s: URLayer[Has[Client[Task]], HttpClient] = ??? What will http4s actually return? In order to answer this question, we need to implement HttpClient.Service first. The Http4s implementation Implementing the get request is straightforward: package pdt.http import io.circe.Decoder import org.http4s.Uri import org.http4s.circe.CirceEntityCodec.circeEntityDecoder import org.http4s.client.Client import org.http4s.client.dsl.Http4sClientDsl import zio._ import zio.interop.catz._ private[http] final case class Http4s(client: Client[Task]) extends HttpClient.Service with Http4sClientDsl[Task] { def get[T](resource: String,  » Read More

Like to keep reading?

This article first appeared on hackernoon.com. If you'd like to keep reading, follow the white rabbit.

View Full Article

Leave a Reply