$ cat learning-effect-11-one-small-real-program.md
Part 11: One Small Real Program
$ tail -f learning-effect-11-one-small-real-program/readers
connecting…
Now I want one small program.
Not a production app.
Not an architecture diagram.
Just enough code to see the pieces touch.
The flow
The program will:
- read a user id from a request
- parse it
- fetch the user
- turn
UserNotFoundinto a 404 response - run once at the edge
That is a real shape.
The core program
const getUserResponse = (input: string) => parseUserId(input).pipe( Effect.flatMap(fetchUser), Effect.map((user) => Response.json(user)), Effect.catchTag("UserNotFound", () => Effect.succeed(new Response("User not found", { status: 404 })), ), );Read it straight down.
Parse.
Fetch.
Turn success into JSON.
Handle one known error.
The type tells the truth
After handling UserNotFound, the type might still say:
Effect.Effect<Response, InvalidUserId, UserRepo>;That means:
- success:
Response - error:
InvalidUserId - requirement:
UserRepo
There is still work to do before running it.
We need to decide what bad input means.
We need to provide UserRepo.
Run it at the edge
export async function GET(request: Request) { const id = new URL(request.url).searchParams.get("id") ?? "";
const program = getUserResponse(id).pipe( Effect.provide(UserRepoLive), Effect.catchTag("InvalidUserId", () => Effect.succeed(new Response("Invalid user id", { status: 400 })), ), );
return Effect.runPromise(program);}The runner appears once.
At the edge.
That feels right.
What I learned from the first pass
Effect is not one idea.
It is a stack of small ideas:
- describe work before running it
- make errors visible
- make dependencies visible
- compose the happy path without losing the failure path
- run the program at the edge
I still have a lot to learn.
But now I can read the first line of the map.
Effect.Effect<Success, Error, Requirements>;That is enough to keep going.
NOTE
Next I would learn schedules, retries, scopes, and streams. But not yet. The basics should feel boring first.