Decoding data from a schema

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";

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 successful
  • ParseError: 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* to decodePokemon, 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.