Created
February 12, 2026 13:44
-
-
Save LuxXx/3f4c74d87be315b410445347768fc71b to your computer and use it in GitHub Desktop.
effect example for marcel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { | |
| HttpClient, | |
| PlatformConfigProvider, | |
| FetchHttpClient, | |
| FileSystem, | |
| Path, | |
| } from "@effect/platform"; | |
| import { BunContext, BunRuntime } from "@effect/platform-bun"; | |
| import { Config, Data, Effect, Redacted, Schema } from "effect"; | |
| const MySchema = Schema.Struct({ | |
| name: Schema.String, | |
| age: Schema.Number, | |
| }); | |
| class MyError extends Data.TaggedError("MyError")<{ | |
| cause?: unknown; | |
| message?: string; | |
| }> {} | |
| // the requirements are never, because this effect doesnt have any dependencies | |
| // Effect.Effect<"OKAY!", MyError, never> | |
| const FailingEffect = Effect.gen(function* () { | |
| const x = Math.random(); | |
| if (x < 0.5) { | |
| return yield* new MyError({ message: "Failed to to something" }); | |
| } | |
| return "OKAY!" as const; | |
| }); | |
| // Effect.Effect<void, MyError | TimeoutException | ParseError | HttpClientError | ConfigError | PlatformError, HttpClient.HttpClient | Path.Path | FileSystem.FileSystem> | |
| const program = Effect.gen(function* () { | |
| const result = yield* Effect.tryPromise({ | |
| try: () => | |
| new Promise<string>((resolve, reject) => { | |
| setTimeout(() => { | |
| resolve("Hello, world!"); | |
| }, 1000); | |
| }), | |
| catch: (error) => new MyError({ cause: error, message: "Failed to to something" }), | |
| }).pipe( | |
| // adding this will let the effect timeout after 2 seconds, if it times out the error will be TimeoutException | |
| Effect.timeout(2000), | |
| ); | |
| const parsed = yield* Schema.decodeUnknown(MySchema)({ name: result, age: 10 }); | |
| // const okayOrRecovered: "OKAY!" | "Failed 3 times but recovered from error" | |
| const okayOrRecovered = yield* FailingEffect.pipe( | |
| // if this effect fails, it will be retried 2 times | |
| Effect.retry({ times: 2 }), | |
| Effect.catchTags({ | |
| MyError: (error) => Effect.succeed("Failed 3 times but recovered from error" as const), | |
| }), | |
| ); | |
| yield* Effect.log({ response: result, parsed, okayOrRecovered }); | |
| const http = yield* HttpClient.HttpClient; | |
| const response = yield* http.get("https://httpbin.org/get"); | |
| const body = yield* response.json; | |
| yield* Effect.log({ body }); | |
| const awsSecretAccessKey = yield* Config.redacted(Config.string("AWS_SECRET_ACCESS_KEY")); | |
| // we can just log it lol | |
| yield* Effect.log({ awsSecretAccessKey }); | |
| const myClientConfig = { | |
| // ok we actually need it now | |
| secretKey: Redacted.value(awsSecretAccessKey), | |
| }; | |
| // when yieldind path or fs we need to provide an implementation of it | |
| const path = yield* Path.Path; | |
| const fs = yield* FileSystem.FileSystem; | |
| // when calling this a scope will be required on the type level | |
| const tmpDir = yield* fs.makeTempDirectoryScoped(); | |
| const arr = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]; | |
| yield* Effect.forEach( | |
| arr, | |
| Effect.fn(function* (item) { | |
| const content = new TextEncoder().encode(item); | |
| const file = yield* fs.writeFile(path.join(tmpDir, item), content); | |
| yield* Effect.log({ file }); | |
| }), | |
| { | |
| concurrency: 3, | |
| }, | |
| ); | |
| }).pipe( | |
| // we give a scope to the effect so it gets cleaned up after the program runs | |
| // try removing this! when calling makeTempDirectoryScoped, a scope will automaitically be required on the type level | |
| Effect.scoped, | |
| ); | |
| program.pipe( | |
| // if we provide this our Config layer will have access to the environment variables in .env | |
| // but once we use this, this effect will need a filesystem (obviously because we are reading a file (.env), so we also provide one) | |
| Effect.provide(PlatformConfigProvider.layerDotEnv(".env")), | |
| // BunContext contains FileSystem, Path and some more stuff | |
| Effect.provide(BunContext.layer), | |
| // when yielding a http client, we need to provide a http client layer | |
| Effect.provide(FetchHttpClient.layer), | |
| BunRuntime.runMain, | |
| ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment