scalaadvanced
ZIO Layers and Dependency Management
Use ZIO ZLayer for dependency injection: service definitions, layer composition, and testing.
scalaPress ⌘/Ctrl + Shift + C to copy
import zio.*
// Service definitions
trait UserRepo:
def findById(id: Long): Task[Option[String]]
def save(name: String): Task[Long]
trait EmailService:
def send(to: String, subject: String, body: String): Task[Unit]
trait UserService:
def register(name: String, email: String): Task[Long]
def getUser(id: Long): Task[Option[String]]
// Implementations
case class UserRepoLive() extends UserRepo:
private var users = scala.collection.mutable.Map(1L -> "Alice")
private var nextId = 2L
def findById(id: Long): Task[Option[String]] =
ZIO.succeed(users.get(id))
def save(name: String): Task[Long] = ZIO.succeed {
val id = nextId; nextId += 1
users(id) = name; id
}
case class EmailServiceLive() extends EmailService:
def send(to: String, subject: String, body: String): Task[Unit] =
ZIO.succeed(println(s" Email to $to: $subject"))
case class UserServiceLive(repo: UserRepo, email: EmailService) extends UserService:
def register(name: String, emailAddr: String): Task[Long] =
for
id <- repo.save(name)
_ <- email.send(emailAddr, "Welcome", s"Hello $name, ID=$id")
yield id
def getUser(id: Long): Task[Option[String]] =
repo.findById(id)
// Layers
object UserRepo:
val live: ZLayer[Any, Nothing, UserRepo] =
ZLayer.succeed(UserRepoLive())
object EmailService:
val live: ZLayer[Any, Nothing, EmailService] =
ZLayer.succeed(EmailServiceLive())
// Test implementation
val test: ZLayer[Any, Nothing, EmailService] =
ZLayer.succeed(new EmailService:
def send(to: String, subject: String, body: String): Task[Unit] =
ZIO.succeed(println(s" [TEST] Would send to $to: $subject"))
)
object UserService:
val live: ZLayer[UserRepo & EmailService, Nothing, UserService] =
ZLayer {
for
repo <- ZIO.service[UserRepo]
email <- ZIO.service[EmailService]
yield UserServiceLive(repo, email)
}
object MyApp extends ZIOAppDefault:
val program: ZIO[UserService, Throwable, Unit] = for
service <- ZIO.service[UserService]
id <- service.register("Bob", "bob@test.com")
_ <- Console.printLine(s"Registered with ID: $id")
user <- service.getUser(id)
_ <- Console.printLine(s"Found: $user")
_ <- Console.printLine(s"Missing: ${service.getUser(99)}")
yield ()
// Compose layers
val appLayer: ZLayer[Any, Nothing, UserService] =
(UserRepo.live ++ EmailService.live) >>> UserService.live
// For testing
val testLayer: ZLayer[Any, Nothing, UserService] =
(UserRepo.live ++ EmailService.test) >>> UserService.live
def run = program.provide(appLayer)Use Cases
- Dependency injection with ZIO
- Testable service architecture
- Layer composition for modular apps
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
scalaadvanced
ZIO Effect System Basics
Build programs with ZIO: effects, error handling, layers, and concurrent operations.
Best for: Typed error handling with ZIO
#scala#zio
scalaadvanced
ZIO Fibers and Concurrency
Use ZIO fibers for lightweight concurrency: fork, join, race, parallel operations, and supervision.
Best for: Lightweight concurrent task execution
#scala#zio
scalabeginner
Scala Hello World Application
Create a basic Scala application with main method, string interpolation, and val/var basics.
Best for: Getting started with Scala
#scala#basics
scalabeginner
Pattern Matching Fundamentals
Use Scala pattern matching with guards, type patterns, tuple patterns, and nested extractors.
Best for: Control flow with pattern matching
#scala#pattern-matching