Defining more services

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 Context to create a service.

For example we can create a PokemonCollection service that contains a non-empty list of string:

PokemonCollection.ts
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.NonEmptyArray from the Array module of effect. This requires PokemonCollection to have at least 1 Pokémon in the list.

Array is 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:

BuildPokeApiUrl.ts
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:

PokeApiUrl.ts
import { Context } from "effect";

export class PokeApiUrl extends Context.Tag("PokeApiUrl")<
  PokeApiUrl,
  // 👇 Even a single `string` works
  string
>() {}