Effect by Example: Making HTTP Requests

Tags:

platformhttp

A very common task in any application is to make HTTP requests to fetch data.

First we’ll look at how to wrap fetch yourself, then we’ll look at how to use @effect/platform’s HTTP client.

Wrapping fetch ourselves

import {
import Data
Data
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Schema
Schema
} from "effect";
class
class RequestError
RequestError
extends
import Data
Data
.
const TaggedError: <"RequestError">(tag: "RequestError") => new <A>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
...;
} & Readonly<...>

@since2.0.0

TaggedError
("RequestError")<{
cause: unknown
cause
: unknown;
}> {}
class
class ResponseError
ResponseError
extends
import Data
Data
.
const TaggedError: <"ResponseError">(tag: "ResponseError") => new <A>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
...;
} & Readonly<...>

@since2.0.0

TaggedError
("ResponseError")<{
status: number
status
: number;
cause: string
cause
: string;
response: Response
response
:
interface Response
Response
;
}> {}
class
class BodyJsonError
BodyJsonError
extends
import Data
Data
.
const TaggedError: <"BodyJsonError">(tag: "BodyJsonError") => new <A>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
...;
} & Readonly<...>

@since2.0.0

TaggedError
("BodyJsonError")<{
cause: unknown
cause
: unknown;
}> {}
const
const User: Schema.Struct<{
id: typeof Schema.Number;
name: typeof Schema.String;
}>
User
=
import Schema
Schema
.
function Struct<{
id: typeof Schema.Number;
name: typeof Schema.String;
}>(fields: {
id: typeof Schema.Number;
name: typeof Schema.String;
}): Schema.Struct<{
id: typeof Schema.Number;
name: typeof Schema.String;
}> (+1 overload)

@since3.10.0

Struct
({
id: typeof Schema.Number
id
:
import Schema
Schema
.
class Number
export Number

@since3.10.0

Number
,
name: typeof Schema.String
name
:
import Schema
Schema
.
class String
export String

@since3.10.0

String
,
});
function
function fetchUser(id: number): Effect.Effect<{
readonly id: number;
readonly name: string;
}, RequestError | ResponseError | BodyJsonError | ParseError, never>
fetchUser
(
id: number
id
: number) {
return
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<Response, RequestError, never>> | YieldWrap<Effect.Effect<never, ResponseError, never>> | YieldWrap<...> | YieldWrap<...>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const response: Response
response
= yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tryPromise: <Response, RequestError>(options: {
readonly try: (signal: AbortSignal) => PromiseLike<Response>;
readonly catch: (error: unknown) => RequestError;
}) => Effect.Effect<...> (+1 overload)

Creates an Effect that represents an asynchronous computation that might fail.

When to Use

In situations where you need to perform asynchronous operations that might fail, such as fetching data from an API, you can use the tryPromise constructor. This constructor is designed to handle operations that could throw exceptions by capturing those exceptions and transforming them into manageable errors.

Error Handling

There are two ways to handle errors with tryPromise:

  1. If you don't provide a catch function, the error is caught and the effect fails with an UnknownException.
  2. If you provide a catch function, the error is caught and the catch function maps it to an error of type E.

Interruptions

An optional AbortSignal can be provided to allow for interruption of the wrapped Promise API.

Example (Fetching a TODO Item)

import { Effect } from "effect"
const getTodo = (id: number) =>
// Will catch any errors and propagate them as UnknownException
Effect.tryPromise(() =>
fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
)
// ┌─── Effect<Response, UnknownException, never>
// ▼
const program = getTodo(1)

Example (Custom Error Handling)

import { Effect } from "effect"
const getTodo = (id: number) =>
Effect.tryPromise({
try: () => fetch(`https://jsonplaceholder.typicode.com/todos/${id}`),
// remap the error
catch: (unknown) => new Error(`something went wrong ${unknown}`)
})
// ┌─── Effect<Response, Error, never>
// ▼
const program = getTodo(1)

@seepromise if the effectful computation is asynchronous and does not throw errors.

@since2.0.0

tryPromise
({
try: (signal: AbortSignal) => PromiseLike<Response>
try
: (
signal: AbortSignal
signal
) =>
function fetch(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response> (+1 overload)

Send a HTTP(s) request

@paraminput URL string or Request object

@paraminit A structured value that contains settings for the fetch() request.

@returnsA promise that resolves to Response object.

fetch
(`https://jsonplaceholder.typicode.com/users/${
id: number
id
}`, {
signal?: AbortSignal | null | undefined
signal
}),
catch: (error: unknown) => RequestError
catch
: (
cause: unknown
cause
) => new
constructor RequestError<{
cause: unknown;
}>(args: {
readonly cause: unknown;
}): RequestError
RequestError
({
cause: unknown
cause
}),
});
if (!
const response: Response
response
.
Response.ok: boolean
ok
) {
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <ResponseError>(error: ResponseError) => Effect.Effect<never, ResponseError, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

Example (Creating a Failed Effect)

import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@seesucceed to create an effect that represents a successful value.

@since2.0.0

fail
(
new
constructor ResponseError<{
status: number;
cause: string;
response: Response;
}>(args: {
readonly status: number;
readonly cause: string;
readonly response: Response;
}): ResponseError
ResponseError
({
cause: string
cause
:
const response: Response
response
.
Response.statusText: string
statusText
,
status: number
status
:
const response: Response
response
.
Response.status: number
status
,
response: Response
response
,
}),
);
}
const
const body: unknown
body
= yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tryPromise: <unknown, BodyJsonError>(options: {
readonly try: (signal: AbortSignal) => PromiseLike<unknown>;
readonly catch: (error: unknown) => BodyJsonError;
}) => Effect.Effect<...> (+1 overload)

Creates an Effect that represents an asynchronous computation that might fail.

When to Use

In situations where you need to perform asynchronous operations that might fail, such as fetching data from an API, you can use the tryPromise constructor. This constructor is designed to handle operations that could throw exceptions by capturing those exceptions and transforming them into manageable errors.

Error Handling

There are two ways to handle errors with tryPromise:

  1. If you don't provide a catch function, the error is caught and the effect fails with an UnknownException.
  2. If you provide a catch function, the error is caught and the catch function maps it to an error of type E.

Interruptions

An optional AbortSignal can be provided to allow for interruption of the wrapped Promise API.

Example (Fetching a TODO Item)

import { Effect } from "effect"
const getTodo = (id: number) =>
// Will catch any errors and propagate them as UnknownException
Effect.tryPromise(() =>
fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
)
// ┌─── Effect<Response, UnknownException, never>
// ▼
const program = getTodo(1)

Example (Custom Error Handling)

import { Effect } from "effect"
const getTodo = (id: number) =>
Effect.tryPromise({
try: () => fetch(`https://jsonplaceholder.typicode.com/todos/${id}`),
// remap the error
catch: (unknown) => new Error(`something went wrong ${unknown}`)
})
// ┌─── Effect<Response, Error, never>
// ▼
const program = getTodo(1)

@seepromise if the effectful computation is asynchronous and does not throw errors.

@since2.0.0

tryPromise
({
try: (signal: AbortSignal) => PromiseLike<unknown>
try
: () =>
const response: Response
response
.
BodyMixin.json: () => Promise<unknown>
json
(),
catch: (error: unknown) => BodyJsonError
catch
: (
cause: unknown
cause
) => new
constructor BodyJsonError<{
cause: unknown;
}>(args: {
readonly cause: unknown;
}): BodyJsonError
BodyJsonError
({
cause: unknown
cause
}),
});
const
const user: {
readonly id: number;
readonly name: string;
}
user
= yield*
import Schema
Schema
.
const decodeUnknown: <{
readonly id: number;
readonly name: string;
}, {
readonly id: number;
readonly name: string;
}, never>(schema: Schema.Schema<{
readonly id: number;
readonly name: string;
}, {
readonly id: number;
readonly name: string;
}, never>, options?: ParseOptions) => (u: unknown, overrideOptions?: ParseOptions) => Effect.Effect<...>

@since3.10.0

decodeUnknown
(
const User: Schema.Struct<{
id: typeof Schema.Number;
name: typeof Schema.String;
}>
User
)(
const body: unknown
body
);
return
const user: {
readonly id: number;
readonly name: string;
}
user
;
});
}
const
const program: Effect.Effect<void, RequestError | ResponseError | BodyJsonError | ParseError, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<{
readonly id: number;
readonly name: string;
}, RequestError | ResponseError | BodyJsonError | ParseError, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const user: {
readonly id: number;
readonly name: string;
}
user
= yield*
function fetchUser(id: number): Effect.Effect<{
readonly id: number;
readonly name: string;
}, RequestError | ResponseError | BodyJsonError | ParseError, never>
fetchUser
(1);
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("Fetched user:",
const user: {
readonly id: number;
readonly name: string;
}
user
);
});
await
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runPromise: <void, RequestError | ResponseError | BodyJsonError | ParseError>(effect: Effect.Effect<void, RequestError | ResponseError | BodyJsonError | ParseError, never>, options?: {
readonly signal?: AbortSignal | undefined;
} | undefined) => Promise<...>

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

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
(
const program: Effect.Effect<void, RequestError | ResponseError | BodyJsonError | ParseError, never>
program
);
Fetched user: {
  id: 1,
  name: "Leanne Graham",
}

In this example, we use different error types for different failure scenarios:

  • RequestError for failures when making the HTTP request
  • ResponseError for response errors (non-2xx status codes)
  • BodyJsonError for JSON parsing failures
  • ParseResult.ParseError (Schema’s built-in error) for validation failure

Using @effect/platform

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Schema
Schema
} from "effect";
import {
import FetchHttpClient
FetchHttpClient
,
import HttpClient
HttpClient
,
import HttpClientResponse
HttpClientResponse
,
} from "@effect/platform";
import {
import NodeHttpClient
NodeHttpClient
} from "@effect/platform-node";
const
const User: Schema.Struct<{
id: typeof Schema.Number;
name: typeof Schema.String;
}>
User
=
import Schema
Schema
.
function Struct<{
id: typeof Schema.Number;
name: typeof Schema.String;
}>(fields: {
id: typeof Schema.Number;
name: typeof Schema.String;
}): Schema.Struct<{
id: typeof Schema.Number;
name: typeof Schema.String;
}> (+1 overload)

@since3.10.0

Struct
({
id: typeof Schema.Number
id
:
import Schema
Schema
.
class Number
export Number

@since3.10.0

Number
,
name: typeof Schema.String
name
:
import Schema
Schema
.
class String
export String

@since3.10.0

String
,
});
const
const fetchUser: (id: number) => Effect.Effect<{
readonly id: number;
readonly name: string;
}, ParseError | HttpClientError, HttpClient.HttpClient>
fetchUser
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fn: <YieldWrap<Effect.Effect<HttpClient.HttpClient.With<HttpClientError, never>, never, HttpClient.HttpClient>> | YieldWrap<...> | YieldWrap<...>, {
...;
}, [id: ...]>(body: (id: number) => Generator<...>) => (id: number) => Effect.Effect<...> (+20 overloads)
fn
(function* (
id: number
id
: number) {
const
const client: HttpClient.HttpClient.With<HttpClientError, never>
client
= yield*
import HttpClient
HttpClient
.
const HttpClient: Tag<HttpClient.HttpClient, HttpClient.HttpClient>

@since1.0.0

@since1.0.0

@since1.0.0

HttpClient
.
Pipeable.pipe<Tag<HttpClient.HttpClient, HttpClient.HttpClient>, Effect.Effect<HttpClient.HttpClient.With<HttpClientError, never>, never, HttpClient.HttpClient>>(this: Tag<...>, ab: (_: Tag<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const map: <HttpClient.HttpClient, HttpClient.HttpClient.With<HttpClientError, never>>(f: (a: HttpClient.HttpClient) => HttpClient.HttpClient.With<HttpClientError, never>) => <E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

Transforms the value inside an effect by applying a function to it.

Syntax

const mappedEffect = pipe(myEffect, Effect.map(transformation))
// or
const mappedEffect = Effect.map(myEffect, transformation)
// or
const mappedEffect = myEffect.pipe(Effect.map(transformation))

Details

map takes a function and applies it to the value contained within an effect, creating a new effect with the transformed value.

It's important to note that effects are immutable, meaning that the original effect is not modified. Instead, a new effect is returned with the updated value.

Example (Adding a Service Charge)

import { pipe, Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const finalAmount = pipe(
fetchTransactionAmount,
Effect.map(addServiceCharge)
)
Effect.runPromise(finalAmount).then(console.log)
// Output: 101

@seemapError for a version that operates on the error channel.

@seemapBoth for a version that operates on both channels.

@seeflatMap or andThen for a version that can return a new effect.

@since2.0.0

map
(
import HttpClient
HttpClient
.
const filterStatusOk: <E, R>(self: HttpClient.HttpClient.With<E, R>) => HttpClient.HttpClient.With<E | ResponseError, R>

Filters responses that return a 2xx status code.

@since1.0.0

filterStatusOk
), // error if non 2xx
);
const
const response: HttpClientResponse.HttpClientResponse
response
= yield*
const client: HttpClient.HttpClient.With<HttpClientError, never>
client
.
HttpClient.With<HttpClientError, never>.get: (url: string | URL, options?: Options.NoBody) => Effect.Effect<HttpClientResponse.HttpClientResponse, HttpClientError, never>
get
(
`https://jsonplaceholder.typicode.com/users/${
id: number
id
}`,
);
const
const user: {
readonly id: number;
readonly name: string;
}
user
= yield*
import HttpClientResponse
HttpClientResponse
.
schemaBodyJson<{
readonly id: number;
readonly name: string;
}, {
readonly id: number;
readonly name: string;
}, never>(schema: Schema.Schema<{
readonly id: number;
readonly name: string;
}, {
readonly id: number;
readonly name: string;
}, never>, options?: ParseOptions | undefined): <E>(self: HttpIncomingMessage<...>) => Effect.Effect<...>
export schemaBodyJson

@since1.0.0

schemaBodyJson
(
const User: Schema.Struct<{
id: typeof Schema.Number;
name: typeof Schema.String;
}>
User
)(
const response: HttpClientResponse.HttpClientResponse
response
);
return
const user: {
readonly id: number;
readonly name: string;
}
user
;
});
const
const program: Effect.Effect<void, ParseError | HttpClientError, HttpClient.HttpClient>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<{
readonly id: number;
readonly name: string;
}, ParseError | HttpClientError, HttpClient.HttpClient>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const user: {
readonly id: number;
readonly name: string;
}
user
= yield*
const fetchUser: (id: number) => Effect.Effect<{
readonly id: number;
readonly name: string;
}, ParseError | HttpClientError, HttpClient.HttpClient>
fetchUser
(1);
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("Fetched user:",
const user: {
readonly id: number;
readonly name: string;
}
user
);
});
await
const program: Effect.Effect<void, ParseError | HttpClientError, HttpClient.HttpClient>
program
.
Pipeable.pipe<Effect.Effect<void, ParseError | HttpClientError, HttpClient.HttpClient>, Effect.Effect<void, ParseError | HttpClientError, never>, Promise<...>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Promise<...>): Promise<...> (+21 overloads)
pipe
(
// provide fetch implementation of HttpClient
// (available on all platforms)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <HttpClient.HttpClient, never, never>(layer: Layer<HttpClient.HttpClient, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<...> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

Example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@seeprovideService for providing a service to an effect.

@since2.0.0

provide
(
import FetchHttpClient
FetchHttpClient
.
const layer: Layer<HttpClient.HttpClient, never, never>

@since1.0.0

layer
),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
,
);
// also available are platform-specific implementations
import NodeHttpClient
NodeHttpClient
.layer ;
layer
layerUndici
layerUndiciWithoutDispatcher
layerWithoutAgent
Fetched user: {
  id: 1,
  name: "Leanne Graham",
}