When organizing the dependencies in a complex app services are not enough anymore. We soon encounter problems with interdependencies and providing services that depend on each other.
Effect offers an better abstraction for this: Layer.
Let's see why this is needed.
Adding more services
We need something more complex to understand the point of Layer.
Let's add some services then.
With effect a service does not need to be a collection of methods. Anything can be wrapped with
Contextto create a service.
For example we can create a PokemonCollection service that contains a non-empty list of string:
import { Context, type Array } from "effect";
export class PokemonCollection extends Context.Tag("PokemonCollection")<
PokemonCollection,
/// 👇 A list of names of your favorite Pokémon
Array.NonEmptyArray<string>
>() {}We use
Array.NonEmptyArrayfrom theArraymodule of effect. This requiresPokemonCollectionto have at least 1 Pokémon in the list.
Arrayis out of scope for this course. It's really handy, I suggest you to explore it on the docs!
A service can also be a single function. We can create a BuildPokeApiUrl service that constructs the PokéApi url endpoint to request a Pokémon:
import { Context } from "effect";
export class BuildPokeApiUrl extends Context.Tag("BuildPokeApiUrl")<
BuildPokeApiUrl,
/// 👇 A single function
(props: { name: string }) => string
>() {}What about a service for a single string? We can do this as well:
import { Context } from "effect";
export class PokeApiUrl extends Context.Tag("PokeApiUrl")<
PokeApiUrl,
// 👇 Even a single `string` works
string
>() {}