The first step was defining the schema we expect from the response. Done ✅
Now we need to use Schema
to verify that the response (unknown
) is a valid Pokemon
.
We do this by using Schema.decodeUnknown
with our custom Pokemon
schema:
import { Schema } from "@effect/schema";
const Pokemon = Schema.Struct({
id: Schema.Number,
order: Schema.Number,
name: Schema.String,
height: Schema.Number,
weight: Schema.Number,
});
const decodePokemon = Schema.decodeUnknown(Pokemon);
The resulting decodePokemon
function takes any unknown
value and returns an Effect<Pokemon, ParseError>
:
Pokemon
: valid object when decoding is successfulParseError
: information about what went wrong in the decoding process
We can then add this to our program
:
const program = Effect.gen(function* () {
const response = yield* fetchRequest;
if (!response.ok) {
return yield* new FetchError();
}
const json = yield* jsonResponse(response);
return yield* decodePokemon(json);
});
Remember to add
yield*
todecodePokemon
, since schema validation is an effectful operation that may fail!
Since we introduced a new ParseError
we need to handle it:
const main = program.pipe(
Effect.catchTags({
FetchError: () => Effect.succeed("Fetch error"),
JsonError: () => Effect.succeed("Json error"),
ParseError: () => Effect.succeed("Parse error"),
})
);
See how straightforward this is? You work on your
program
, then check its type to inspect what may go wrong, and handle everything that's needed.You will come to appreciate this even more when your app starts to scale in complexity.