You may have noticed a type error when running main:
Type 'PokeApiUrl' is not assignable to type 'never'.That's a missing dependency! Why PokeApiUrl is missing? Didn't we already provide PokeApiUrl to Layer.mergeAll?
const MainLayer = Layer.mergeAll(
PokeApi.Live,
PokemonCollection.Live,
BuildPokeApiUrl.Live,
PokeApiUrl.Live
);Yes, but we have a dependency between layers that we didn't resolve: the BuildPokeApiUrl layer depends on PokeApiUrl.
export class BuildPokeApiUrl extends Context.Tag("BuildPokeApiUrl")<
BuildPokeApiUrl,
({ name }: { name: string }) => string
>() {
static readonly Live = Layer.effect(
this,
Effect.gen(function* () {
const pokeApiUrl = yield* PokeApiUrl; // 👈 Create dependency
return ({ name }) => `${pokeApiUrl}/${name}`;
})
);
}If we check the type of BuildPokeApiUrl.Live we see the following: Layer.Layer<BuildPokeApiUrl, never, PokeApiUrl>.
Since the full service requires PokeApiUrl, we need to provide it directly to BuildPokeApiUrl.
We do this by using Layer.provide:
const MainLayer = Layer.mergeAll(
PokeApi.Live,
PokemonCollection.Live,
BuildPokeApiUrl.Live.pipe(Layer.provide(PokeApiUrl.Live)),
PokeApiUrl.Live
);We use
Layer.providewhen composing layers, andEffect.providewhen providing the final layer to run effects.
Layer.provideandEffect.provideare two different APIs!
Now our program compiles and works:
import { Effect, Layer } from "effect";
import { BuildPokeApiUrl } from "./BuildPokeApiUrl";
import { PokeApi } from "./PokeApi";
import { PokeApiUrl } from "./PokeApiUrl";
import { PokemonCollection } from "./PokemonCollection";
const MainLayer = Layer.mergeAll(
PokeApi.Live,
PokemonCollection.Live,
BuildPokeApiUrl.Live.pipe(Layer.provide(PokeApiUrl.Live)),
PokeApiUrl.Live
);
export const program = Effect.gen(function* () {
const pokeApi = yield* PokeApi;
return yield* pokeApi.getPokemon;
});
const runnable = program.pipe(Effect.provide(MainLayer));
const main = runnable.pipe(
Effect.catchTags({
FetchError: () => Effect.succeed("Fetch error"),
JsonError: () => Effect.succeed("Json error"),
ParseError: () => Effect.succeed("Parse error"),
})
);
Effect.runPromise(main).then(console.log);> effect-getting-started-course@1.0.0 dev
> BASE_URL=https://pokeapi.co tsx src/index.ts
{ id: 120, order: 191, name: 'staryu', height: 8, weight: 345 }