Effect.Effect<Client.HttpClient, never, HttpAgent>Creates an HttpClient backed by Node http and https, using the
current HttpAgent, streaming request bodies, and wrapping Node responses
as HttpClientResponse values.
export const const makeNodeHttp: Effect.Effect<
Client.HttpClient,
never,
HttpAgent
>
const makeNodeHttp: {
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
Creates an HttpClient backed by Node http and https, using the
current HttpAgent, streaming request bodies, and wrapping Node responses
as HttpClientResponse values.
makeNodeHttp = import EffectEffect.const gen: {
<Eff extends Effect<any, any, any>, AEff>(
f: () => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
<Self, Eff extends Effect<any, any, any>, AEff>(
options: { readonly self: Self },
f: (this: Self) => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
}
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
Example (Sequencing effects with generators)
import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: 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}`
})
gen(function*() {
const const agent: {
readonly http: Http.Agent
readonly https: Https.Agent
}
agent = yield* class HttpAgentclass HttpAgent {
key: Identifier;
Service: {
http: Http.Agent;
https: Https.Agent;
};
of: (this: void, self: { readonly http: Http.Agent; readonly https: Https.Agent }) => { readonly http: Http.Agent; readonly https: Https.Agent };
context: (self: { readonly http: Http.Agent; readonly https: Https.Agent }) => Context.Context<HttpAgent>;
use: (f: (service: { readonly http: Http.Agent; readonly https: Https.Agent }) => Effect.Effect<A, E, R>) => Effect.Effect<A, E, HttpAgent | R>;
useSync: (f: (service: { readonly http: Http.Agent; readonly https: Https.Agent }) => A) => Effect.Effect<A, never, HttpAgent>;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
Service tag for the paired Node http and https agents used by the
node:http-backed HTTP client.
HttpAgent
return import ClientClient.const make: (
f: (
request: HttpClientRequest.HttpClientRequest,
url: URL,
signal: AbortSignal,
fiber: Fiber.Fiber<
HttpClientResponse.HttpClientResponse,
Error.HttpClientError
>
) => Effect.Effect<
HttpClientResponse.HttpClientResponse,
Error.HttpClientError
>
) => HttpClient
Constructs an HttpClient from a low-level request runner.
Details
The runner receives the request, resolved URL, abort signal, and current fiber. The client wrapper handles URL construction failures, tracing and propagation, header redaction, and aborting non-scoped requests on interruption.
make((request: HttpClientRequest(parameter) request: {
method: HttpMethod;
url: string;
urlParams: UrlParams.UrlParams;
hash: Option.Option<string>;
headers: Headers.Headers;
body: HttpBody.HttpBody;
toString: () => string;
toJSON: () => unknown;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
request, url: URLurl, signal: AbortSignalsignal) => {
const const nodeRequest: anynodeRequest = url: URLurl.URL.protocol: stringThe protocol property of the URL interface is a string containing the protocol or scheme of the URL, including the final ':'.
protocol === "https:" ?
import HttpsHttps.request(url: URLurl, {
agent: Https.Agentagent: const agent: {
readonly http: Http.Agent
readonly https: Https.Agent
}
agent.https: Https.Agenthttps,
method: HttpMethodmethod: request: HttpClientRequest(parameter) request: {
method: HttpMethod;
url: string;
urlParams: UrlParams.UrlParams;
hash: Option.Option<string>;
headers: Headers.Headers;
body: HttpBody.HttpBody;
toString: () => string;
toJSON: () => unknown;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
request.HttpClientRequest.method: HttpMethodmethod,
headers: Headers.Headersheaders: request: HttpClientRequest(parameter) request: {
method: HttpMethod;
url: string;
urlParams: UrlParams.UrlParams;
hash: Option.Option<string>;
headers: Headers.Headers;
body: HttpBody.HttpBody;
toString: () => string;
toJSON: () => unknown;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
request.HttpClientRequest.headers: Headers.Headersheaders,
signal: AbortSignalsignal
}) :
import HttpHttp.request(url: URLurl, {
agent: Http.Agentagent: const agent: {
readonly http: Http.Agent
readonly https: Https.Agent
}
agent.http: Http.Agenthttp,
method: HttpMethodmethod: request: HttpClientRequest(parameter) request: {
method: HttpMethod;
url: string;
urlParams: UrlParams.UrlParams;
hash: Option.Option<string>;
headers: Headers.Headers;
body: HttpBody.HttpBody;
toString: () => string;
toJSON: () => unknown;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
request.HttpClientRequest.method: HttpMethodmethod,
headers: Headers.Headersheaders: request: HttpClientRequest(parameter) request: {
method: HttpMethod;
url: string;
urlParams: UrlParams.UrlParams;
hash: Option.Option<string>;
headers: Headers.Headers;
body: HttpBody.HttpBody;
toString: () => string;
toJSON: () => unknown;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
request.HttpClientRequest.headers: Headers.Headersheaders,
signal: AbortSignalsignal
})
return import EffectEffect.const forkChild: <
Arg extends
| Effect<any, any, any>
| {
readonly startImmediately?:
| boolean
| undefined
readonly uninterruptible?:
| boolean
| "inherit"
| undefined
}
| undefined = {
readonly startImmediately?:
| boolean
| undefined
readonly uninterruptible?:
| boolean
| "inherit"
| undefined
}
>(
effectOrOptions?: Arg,
options?:
| {
readonly startImmediately?:
| boolean
| undefined
readonly uninterruptible?:
| boolean
| "inherit"
| undefined
}
| undefined
) => [Arg] extends [
Effect<infer _A, infer _E, infer _R>
]
? Effect<Fiber<_A, _E>, never, _R>
: <A, E, R>(
self: Effect<A, E, R>
) => Effect<Fiber<A, E>, never, R>
Returns an effect that forks this effect into its own separate fiber,
returning the fiber immediately, without waiting for it to begin executing
the effect.
Details
You can use the forkChild method whenever you want to execute an effect in a
new fiber, concurrently and without "blocking" the fiber executing other
effects. Using fibers can be tricky, so instead of using this method
directly, consider other higher-level methods, such as raceWith,
zipPar, and so forth.
The fiber returned by this method has methods to interrupt the fiber and to
wait for it to finish executing the effect. See Fiber for more
information.
Whenever you use this method to launch a new fiber, the new fiber is
attached to the parent fiber's scope. This means when the parent fiber
terminates, the child fiber will be terminated as well, ensuring that no
fibers leak. This behavior is called "auto supervision", and if this
behavior is not desired, you may use the forkDetach or forkIn methods.
Example (Forking a child fiber)
import { Effect, Fiber } from "effect"
const longRunningTask = Effect.gen(function*() {
yield* Effect.sleep("2 seconds")
yield* Effect.log("Task completed")
return "result"
})
const program = Effect.gen(function*() {
const fiber = yield* longRunningTask.pipe(Effect.forkChild)
// or fork a fiber that starts immediately:
yield* longRunningTask.pipe(Effect.forkChild({ startImmediately: true }))
yield* Effect.log("Task forked, continuing...")
const result = yield* Fiber.join(fiber)
return result
})
forkChild(const sendBody: (
nodeRequest: Http.ClientRequest,
request: HttpClientRequest,
body: Body.HttpBody
) => Effect.Effect<void, Error.HttpClientError>
sendBody(const nodeRequest: anynodeRequest, request: HttpClientRequest(parameter) request: {
method: HttpMethod;
url: string;
urlParams: UrlParams.UrlParams;
hash: Option.Option<string>;
headers: Headers.Headers;
body: HttpBody.HttpBody;
toString: () => string;
toJSON: () => unknown;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
request, request: HttpClientRequest(parameter) request: {
method: HttpMethod;
url: string;
urlParams: UrlParams.UrlParams;
hash: Option.Option<string>;
headers: Headers.Headers;
body: HttpBody.HttpBody;
toString: () => string;
toJSON: () => unknown;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
request.HttpClientRequest.body: Body.HttpBodybody)).Pipeable.pipe<Effect.Effect<Fiber<void, Error.HttpClientError>, never, never>, Effect.Effect<Http.IncomingMessage, Error.HttpClientError, never>, Effect.Effect<NodeHttpResponse, Error.HttpClientError, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<Fiber<void, Error.HttpClientError>, never, never>) => Effect.Effect<Http.IncomingMessage, Error.HttpClientError, never>, bc: (_: Effect.Effect<Http.IncomingMessage, Error.HttpClientError, never>) => Effect.Effect<NodeHttpResponse, Error.HttpClientError, never>): Effect.Effect<...> (+21 overloads)pipe(
import EffectEffect.const flatMap: {
<A, B, E1, R1>(
f: (a: A) => Effect<B, E1, R1>
): <E, R>(
self: Effect<A, E, R>
) => Effect<B, E1 | E, R1 | R>
<A, E, R, B, E1, R1>(
self: Effect<A, E, R>,
f: (a: A) => Effect<B, E1, R1>
): Effect<B, E | E1, R | R1>
}
Chains effects to produce new Effect instances, useful for combining
operations that depend on previous results.
When to use
Use when you need to chain multiple effects, ensuring that each
step produces a new Effect while flattening any nested effects that may
occur.
Details
flatMap lets you sequence effects so that the result of one effect can be
used in the next step. It is similar to flatMap used with arrays but works
specifically with Effect instances, allowing you to avoid deeply nested
effect structures.
Since effects are immutable, flatMap always returns a new effect instead of
changing the original one.
Example (Choosing flatMap syntax variants)
import { Effect, pipe } from "effect"
const myEffect = Effect.succeed(1)
const transformation = (n: number) => Effect.succeed(n + 1)
const flatMappedWithPipe = pipe(myEffect, Effect.flatMap(transformation))
const flatMappedWithDataFirst = Effect.flatMap(myEffect, transformation)
const flatMappedWithMethod = myEffect.pipe(Effect.flatMap(transformation))
Example (Sequencing dependent effects)
import { Data, Effect, pipe } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
// Function to apply a discount safely to a transaction amount
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
// Simulated asynchronous task to fetch a transaction amount from database
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
// Chaining the fetch and discount application using `flatMap`
const finalAmount = pipe(
fetchTransactionAmount,
Effect.flatMap((amount) => applyDiscount(amount, 5))
)
Effect.runPromise(finalAmount).then(console.log)
// Output: 95
flatMap(() => const waitForResponse: (
nodeRequest: Http.ClientRequest,
request: HttpClientRequest
) => Effect.Effect<
Http.IncomingMessage,
Error.HttpClientError,
never
>
waitForResponse(const nodeRequest: anynodeRequest, request: HttpClientRequest(parameter) request: {
method: HttpMethod;
url: string;
urlParams: UrlParams.UrlParams;
hash: Option.Option<string>;
headers: Headers.Headers;
body: HttpBody.HttpBody;
toString: () => string;
toJSON: () => unknown;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
request)),
import EffectEffect.const map: {
<A, B>(f: (a: A) => B): <E, R>(
self: Effect<A, E, R>
) => Effect<B, E, R>
<A, E, R, B>(
self: Effect<A, E, R>,
f: (a: A) => B
): Effect<B, E, R>
}
Transforms the value inside an effect by applying a function to it.
When to use
Use to transform an effect's success value with a function that returns a
plain value, producing a new effect without changing the original effect's
typed error or context requirements.
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 (Choosing map syntax variants)
import { Effect, pipe } from "effect"
const myEffect = Effect.succeed(1)
const transformation = (n: number) => n + 1
const mappedWithPipe = pipe(myEffect, Effect.map(transformation))
const mappedWithDataFirst = Effect.map(myEffect, transformation)
const mappedWithMethod = myEffect.pipe(Effect.map(transformation))
Example (Adding a service charge)
import { Effect, pipe } 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
map((_: any_) => new constructor NodeHttpResponse(request: HttpClientRequest, source: Http.IncomingMessage): NodeHttpResponseNodeHttpResponse(request: HttpClientRequest(parameter) request: {
method: HttpMethod;
url: string;
urlParams: UrlParams.UrlParams;
hash: Option.Option<string>;
headers: Headers.Headers;
body: HttpBody.HttpBody;
toString: () => string;
toJSON: () => unknown;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
request, _: any_))
)
})
})