Skip to content

Instantly share code, notes, and snippets.

@hohonuuli
Last active April 9, 2025 17:46
Show Gist options
  • Save hohonuuli/ab532acad9606f5b31df2faccce404c6 to your computer and use it in GitHub Desktop.
Save hohonuuli/ab532acad9606f5b31df2faccce404c6 to your computer and use it in GitHub Desktop.
Example of using Circe with java.net.http
#!/usr/bin/env -S scala
// Brian Schlining. 2024-12-22
//> using dep "io.circe::circe-core:0.14.10"
//> using dep "io.circe::circe-generic:0.14.10"
//> using dep "io.circe::circe-parser:0.14.10"
import io.circe.Decoder
import io.circe.generic.semiauto.deriveDecoder
import io.circe.parser.decode
import java.net.URI
import java.net.http.{HttpClient, HttpRequest, HttpResponse}
import java.nio.charset.StandardCharsets
// --- JSON Decoding ---
// Circe uses case classes to represent JSON objects
final case class Names(items: List[String], limit: Int, offset: Int, total: Int)
// Circe can automatically derive a Decoder for a case class
given Decoder[Names] = deriveDecoder[Names]
// This is a custom BodyHandler that uses Circe to decode the response body.
// It can decode any type T for which there is an implicit Decoder[T] in scope.
class CirceBodyHandler[T: Decoder] extends HttpResponse.BodyHandler[Either[Throwable, T]]:
override def apply(responseInfo: HttpResponse.ResponseInfo): HttpResponse.BodySubscriber[Either[Throwable, T]] =
HttpResponse
.BodySubscribers
.mapping(HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8), s => decode[T](s))
// Factory method for creating a CirceBodyHandler. This isn't strictly necessary,
// but it follows the java.net.http.HttpResponse.BodyHandlers factory method styles
object CirceBodyHandler:
def of[T: Decoder]: CirceBodyHandler[T] = new CirceBodyHandler[T]()
// -- Using the CirceBodyHandler with HttpClient --
val uri = URI.create("https://database.fathomnet.org/worms/names")
val client = HttpClient.newHttpClient();
val request = HttpRequest
.newBuilder()
.uri(uri)
.header("Accept", "application/json")
.GET()
.build()
val response = client.send(request, CirceBodyHandler.of[Names])
response.body() match
case Left(e) => println(s"Failed to parse response: $e")
case Right(names) => println(s"Names: $names")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment