Structured errors
There is a basic example of fetching JSON with schema validation.
We have all fetch errors handled through the Effect error channel. Potencial problems with JSONs are also handled.
import { import Effect
Effect, import Schema
Schema } from "effect";import { import Fetch
Fetch, import Request
Request } from "fx-fetch";
class class User
User extends import Schema
Schema.const Class: <User>(identifier: string) => <Fields>(fieldsOr: Fields | HasFields<Fields>, annotations?: ClassAnnotations<User, { [K in keyof Schema.Struct<Fields extends Schema.Struct.Fields>.Type<Fields>]: Schema.Struct.Type<Fields>[K]; }> | undefined) => Schema.Class<User, Fields, Schema.Struct.Encoded<Fields>, Schema.Schema<in out A, in out I = A, out R = never>.Context<Fields[keyof Fields]>, Schema.Struct.Constructor<Fields>, {}, {}>
Class<class User
User>("User")({ id: typeof Schema.Int
id: import Schema
Schema.class Int
Int, firstName: typeof Schema.String
firstName: import Schema
Schema.class Stringexport String
String, lastName: typeof Schema.String
lastName: import Schema
Schema.class Stringexport String
String,}) { }
// ┌─ (id: number) => Effect.Effect<// │ User,// │ | Fetch.AbortError// │ | Fetch.FetchError// │ | Fetch.NotAllowedError// │ | Response.NotOkError// │ | MalformedJsonError// │ | ParseError,// │ Fetch.Fetch// │ >// ▼const const getUser: (id: number) => Effect.Effect<User, Fetch.AbortError | Fetch.FetchError | Fetch.NotAllowedError | NotOkError | MalformedJsonError | ParseError, Fetch.Fetch>
getUser = import Effect
Effect.const fn: <YieldWrap<Effect.Effect<User, Fetch.AbortError | Fetch.FetchError | Fetch.NotAllowedError | NotOkError | MalformedJsonError | ParseError, Fetch.Fetch>>, User, [id: number]>(body: (id: number) => Generator<YieldWrap<Effect.Effect<User, Fetch.AbortError | Fetch.FetchError | Fetch.NotAllowedError | NotOkError | MalformedJsonError | ParseError, Fetch.Fetch>>, User, never>) => (id: number) => Effect.Effect<...> (+20 overloads)
fn(function* (id: number
id: number) { const const req: Request.Request
req = import Request
Request.function unsafeMake(input: Request.Request.Input): Request.Requestexport unsafeMake
Creates a immutable Request object. Throws an error if the input is invalid.
unsafeMake({ url: string
url: `https://dummyjson.com/users/${id: number
id}` }); const const payload: User
payload = yield* import Fetch
Fetch.fetchJsonWithSchema<User, { readonly id: number; readonly firstName: string; readonly lastName: string;}, never>(request: Request.Request, schema: Schema.Schema<User, { readonly id: number; readonly firstName: string; readonly lastName: string;}, never>): Effect.Effect<User, Fetch.AbortError | Fetch.FetchError | Fetch.NotAllowedError | NotOkError | MalformedJsonError | ParseError, Fetch.Fetch> (+1 overload)export fetchJsonWithSchema
Fetches and reads a JSON response with the given schema.
fetchJsonWithSchema(const req: Request.Request
req, class User
User);
// User ╶─┐ // ▼ return const payload: User
payload;});
await const getUser: (id: number) => Effect.Effect<User, Fetch.AbortError | Fetch.FetchError | Fetch.NotAllowedError | NotOkError | MalformedJsonError | ParseError, Fetch.Fetch>
getUser(1).Pipeable.pipe<Effect.Effect<User, Fetch.AbortError | Fetch.FetchError | Fetch.NotAllowedError | NotOkError | MalformedJsonError | ParseError, Fetch.Fetch>, Effect.Effect<User, Fetch.AbortError | Fetch.FetchError | Fetch.NotAllowedError | NotOkError | MalformedJsonError | ParseError, never>, Promise<User>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<User, Fetch.AbortError | ... 4 more ... | ParseError, Fetch.Fetch>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Promise<...>): Promise<...> (+21 overloads)
pipe( // Handle errors here import Effect
Effect.const provideService: <Fetch.Fetch, (request: Request.Request) => Effect.Effect<Fetch.Fetch.SuccessType, Fetch.Fetch.ErrorType, never>>(tag: Tag<Fetch.Fetch, (request: Request.Request) => Effect.Effect<Fetch.Fetch.SuccessType, Fetch.Fetch.ErrorType, never>>, service: (request: Request.Request) => Effect.Effect<Fetch.Fetch.SuccessType, Fetch.Fetch.ErrorType, never>) => <A, E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)
Provides an implementation for a service in the context of an effect.
Details
This function allows you to supply a specific implementation for a service
required by an effect. Services are typically defined using Context.Tag,
which acts as a unique identifier for the service. By using this function,
you link the service to its concrete implementation, enabling the effect to
execute successfully without additional requirements.
For example, you can use this function to provide a random number generator,
a logger, or any other service your effect depends on. Once the service is
provided, all parts of the effect that rely on the service will automatically
use the implementation you supplied.
Example
import { Effect, Context } from "effect"
// Declaring a tag for a service that generates random numbersclass Random extends Context.Tag("MyRandomService")< Random, { readonly next: Effect.Effect<number> }>() {}
// Using the serviceconst program = Effect.gen(function* () { const random = yield* Random const randomNumber = yield* random.next console.log(`random number: ${randomNumber}`)})
// Providing the implementation//// ┌─── Effect<void, never, never>// ▼const runnable = Effect.provideService(program, Random, { next: Effect.sync(() => Math.random())})
// Run successfullyEffect.runPromise(runnable)// Example Output:// random number: 0.8241872233134417
provideService(import Fetch
Fetch.class Fetch
export Fetch
Fetch service for making or mocking HTTP requests.
Fetch, import Fetch
Fetch.const FetchLive: (request: Request.Request) => Effect.Effect<Fetch.Fetch.SuccessType, Fetch.Fetch.ErrorType, never>export FetchLive
Live implementation of the Fetch service that performs actual HTTP requests.
FetchLive), import Effect
Effect.const runPromise: <A, E>(effect: Effect.Effect<A, E, never>, options?: { readonly signal?: AbortSignal | undefined;} | undefined) => Promise<A>
Executes an effect and returns the result as a Promise.
Details
This function runs an effect and converts its result into a Promise. If the
effect succeeds, the Promise will resolve with the successful result. If
the effect fails, the Promise will reject with an error, which includes the
failure details of the effect.
The optional options parameter allows you to pass an AbortSignal for
cancellation, enabling more fine-grained control over asynchronous tasks.
When to Use
Use this function when you need to execute an effect and work with its result
in a promise-based system, such as when integrating with third-party
libraries that expect Promise results.
Example (Running a Successful Effect as a Promise)
import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)// Output: 1
Example (Handling a Failing Effect as a Rejected Promise)
import { Effect } from "effect"
Effect.runPromise(Effect.fail("my error")).catch(console.error)// Output:// (FiberFailure) Error: my error
runPromise,);Conclusion
Section titled “Conclusion”If you are familiar with EffectTS then this example should look very straightforward. The Fx-Fetch library uses same principles and patterns.
Happy effectful coding!