ZIO 2: Passing a ZLayer value to an application, getting a return value, and handling possible errors

As a little note today, here’s an example ZIO 2 application where I do the following:

  • Pass a value to the ZIO application (named app) from run using a ZLayer
  • Use that ZLayer value in the application
  • Pass a result value from the application back to the run value
  • Use that value in run
  • Handle any possible errors in run with foldZIO
  • Show other ways to write the run value/function

ZIO/ZLayer example

Given that introduction, here’s the ZIO source code:

import zio.*

case class EmailConfig(address: String)

def emailLive(address: String): ULayer[EmailConfig] =
    ZLayer.succeed(EmailConfig(address))

/**
 * A test where I (a) provide a value to `app` using ZLayer and also
 * (b) get a value back from `app` and use that value inside `run`,
 * while also (c) accounting for possible errors.
 */
object ZioPassValueBackToRun extends ZIOAppDefault:

    val app: ZIO[EmailConfig, Throwable, Int] = for
        emailConfig <- ZIO.service[EmailConfig]
        _           <- Console.printLine(s"EMAIL: ${emailConfig.address}")
    yield
        42  // pass this value back to `run`

    // [1]
    val run: ZIO[Any, Throwable, Unit] =
        app.provide(emailLive("coyote@acme.com"))
           .foldZIO(
                failure => Console.printLineError(s"FAILURE = $failure"),
                success => Console.printLine(     s"SUCCESS = $success")
            )

    // [2]
    // val run: ZIO[Any, Throwable, Unit] =
    //    app.provide(emailLive("coyote@acme.com")).tap { result =>
    //        Console.printLine(s"RESULT: $result")
    //    }.unit    // OR .exitCode here

    // [3]
    // val run: ZIO[Any, Throwable, Unit] =
    //    app.provide(emailLive("coyote@acme.com")).mapError { err =>
    //        Exception(s"ERROR: $err")
    //    }.flatMap { result =>
    //        Console.printLine(s"SUCCESS = $result")
    //    }

Note that I use option 1 to handle run in this code, and I also show two other ways the run value could be implemented, especially when (a) you want to get a value back from the application, and (b) also account for possible errors in the application.

Note that I also show all the ZIO type signatures in the application, so you can follow along more easily here.

As a little summary, if you needed a ZIO 2 example that does these things, I hope this is helpful.