Skip to content

Latest commit

 

History

History
96 lines (77 loc) · 3.17 KB

File metadata and controls

96 lines (77 loc) · 3.17 KB
id schema-api-response-basic
title Basic API Response Decoding
category validating-api-responses
skillLevel beginner
tags
schema
api
decode
runtime-validation
http
lessonOrder 5
rule
description
Basic API Response Decoding using Schema.
summary You're fetching data from an external API. The response is `unknown` at runtime. TypeScript's type assertions (`as User`) are lies—they don't validate anything. A malformed API response will silently...

Problem

You're fetching data from an external API. The response is unknown at runtime. TypeScript's type assertions (as User) are lies—they don't validate anything. A malformed API response will silently corrupt your application state.

You need runtime validation that:

  • Fails fast on invalid data
  • Gives you typed errors in the Effect channel, not thrown exceptions
  • Integrates cleanly with Effect pipelines
  • Provides clear error messages for debugging

Solution

import { Effect, Schema } from "effect"

// 1. Define the expected shape
const User = Schema.Struct({
  id: Schema.Number,
  name: Schema.String,
  email: Schema.String,
})

// 2. Derive the TypeScript type
type User = typeof User.Type

// 3. Create a decoder Effect
const parseUser = Schema.decodeUnknown(User)

// 4. Use in an Effect pipeline
const fetchUser = (id: number) =>
  Effect.gen(function* () {
    // Fetch from API
    const response = yield* Effect.tryPromise(() =>
      fetch(`https://api.example.com/users/${id}`).then((r) => r.json())
    )

    // Validate response against schema
    const user = yield* parseUser(response)

    // user is typed as User, and validated at runtime
    console.log(`Fetched user: ${user.name} <${user.email}>`)
    return user
  })

// Handle the result
const main = Effect.gen(function* () {
  const user = yield* fetchUser(123)
  yield* Effect.log(`User email: ${user.email}`)
})

await Effect.runPromise(main)

Why This Works

Concept Explanation
Schema.Struct Defines expected object shape with runtime + compile-time types—single source of truth
Schema.decodeUnknown Returns Effect<A, ParseError> — validation errors flow through Effect's error channel, never thrown
typeof User.Type Extracts the TypeScript type from the schema—keeps type and validation in sync
Effect.gen Sequences async operations cleanly, errors propagate automatically through the pipeline
ParseError Contains detailed error info: what field failed, what was expected, what was received

When to Use

  • Fetching data from external REST APIs
  • Parsing webhook payloads
  • Processing data crossing trust boundaries
  • Validating responses before passing to domain logic
  • Any unknown data that needs type safety

Related Patterns