{"id":16396309,"url":"https://github.com/joshamaju/effect-fetch","last_synced_at":"2025-10-26T14:31:17.549Z","repository":{"id":207156519,"uuid":"718564936","full_name":"joshamaju/effect-fetch","owner":"joshamaju","description":"💪🏽 fetch but with super-powers for effect","archived":false,"fork":false,"pushed_at":"2024-08-26T09:10:01.000Z","size":148,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-31T20:43:56.715Z","etag":null,"topics":["ajax","fetch","http","request"],"latest_commit_sha":null,"homepage":"https://joshamaju.github.io/effect-fetch/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joshamaju.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-11-14T10:50:50.000Z","updated_at":"2024-08-26T18:03:50.000Z","dependencies_parsed_at":"2023-11-23T17:28:16.683Z","dependency_job_id":"5d1c0725-5622-4bf9-8e2e-0612416dc6d3","html_url":"https://github.com/joshamaju/effect-fetch","commit_stats":null,"previous_names":["joshamaju/effect-fetch"],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshamaju%2Feffect-fetch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshamaju%2Feffect-fetch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshamaju%2Feffect-fetch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshamaju%2Feffect-fetch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joshamaju","download_url":"https://codeload.github.com/joshamaju/effect-fetch/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238347680,"owners_count":19456970,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ajax","fetch","http","request"],"created_at":"2024-10-11T05:07:01.072Z","updated_at":"2025-10-26T14:31:17.015Z","avatar_url":"https://github.com/joshamaju.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# effect-fetch\n\n[![Publish to npm](https://github.com/joshamaju/effect-fetch/actions/workflows/release.yml/badge.svg)](https://github.com/joshamaju/effect-fetch/actions/workflows/release.yml)\n\n`fetch` but with super-powers\n\n- 🖇 Interceptors\n- 🔐 Strongly typed errors\n- 🕓 Timeouts\n\n## Install\n\n```bash\nnpm install effect-fetch effect\n```\n\n```bash\nyarn add effect-fetch effect\n```\n\n```bash\npnpm add effect-fetch effect\n```\n\n```html\n\u003cscript src=\"https://unpkg.com/effect-fetch/dist/index.js\"\u003e\u003c/script\u003e\n```\n\n\u003e `effect` is a required peer dependency\n\n## Example\n\n```ts\nimport * as Effect from \"effect/Effect\";\n\nimport * as Fetch from \"effect-fetch/Fetch\";\nimport * as Result from \"effect-fetch/Response\";\nimport * as Adapter from \"effect-fetch/Adapters/Fetch\";\n\nconst program = Effect.gen(function* () {\n  const result = yield* Fetch.fetch(\"/users\");\n  const res = yield* Result.filterStatusOk(result);\n  const users = yield* Result.json(res);\n});\n\n// or\nconst program = Effect.gen(function* () {\n  const fetch = yield* Fetch.Fetch;\n  const result = yield* fetch(\"/users\");\n  const res = yield* Result.filterStatusOk(result);\n  const users = yield* Result.json(res);\n});\n```\n\n### With interceptor\n\n```ts\nimport * as Interceptor from \"effect-fetch/Interceptor\";\nimport { Url as BaseURL } from \"effect-fetch/interceptors/Url\";\n\nconst baseURL = \"https://reqres.in/api\";\n\n// our list of interceptors\nconst interceptors = Interceptor.of(BaseURL(baseURL));\n\n// make function that executes our interceptors\nconst interceptor = Interceptor.provide(\n  Interceptor.make(interceptors),\n  Adapter.fetch\n);\n\n// we finally make the HTTP adapter using the native Fetch API\nconst adapter = Fetch.effect(interceptor);\n\nconst result = await Effect.runPromise(Effect.provide(program, adapter));\n```\n\n## POST Request\n\n```ts\nconst program = Effect.gen(function* () {\n  const result = yield* Fetch.fetch(\"/users\", { method: \"POST\" });\n  const res = yield* Result.filterStatusOk(result);\n  const users = yield* Result.json(res);\n});\n```\n\n## Interceptors\n\n`effect-fetch` ships with default interceptors\n\n- Base URL\n- Timeout\n- Logger\n- Status Filter\n- Bearer and Basic authentication\n\n### Status Filter\n\nTo avoid manually forking the response into the error and success paths\n\n```ts\nconst program = pipe(\n  Fetch.fetch(\"/users\"),\n  // equivalent to response.ok ? response.json() : // handle not ok status\n  Effect.flatMap((response) =\u003e Result.filterStatusOk(response)),\n  Effect.flatMap((response) =\u003e response.json()),\n  Effect.catchTag(\"StatusError\", (error) =\u003e error)\n);\n```\n\nWe can delegate that to an interceptor. So we can decode the response body without worrying about the OK status\n\n```ts\nconst program = pipe(\n  Fetch.fetch(\"/users\"),\n  Effect.flatMap((response) =\u003e response.json())\n);\n\nconst interceptors = Interceptor.of(StatusOK);\n\nconst interceptor = Interceptor.provide(\n  Interceptor.make(interceptors),\n  Adapter.fetch\n);\n\nconst adapter = Fetch.effect(interceptor);\n\nconst result = await program.pipe(\n  Effect.provide(adapter),\n  Effect.catchTag(\"StatusError\", (error) =\u003e error),\n  Effect.runPromise\n);\n```\n\n### Writing your own interceptor\n\n```ts\nimport * as Interceptor from \"effect-fetch/Interceptor\";\n\nconst program = Effect.gen(function* () {\n  const chain = yield* Interceptor.Chain;\n  const clone = chain.request.clone(); // do something with request\n  const response = yield* chain.proceed(chain.request);\n  // do something with response\n  return response;\n});\n```\n\n\u003e Interceptors are executed in the order which they were added (top to bottom).\n\n## Error handling\n\n```ts\nimport * as Interceptor from \"effect-fetch/Interceptor\";\nimport { StatusOK } from \"effect-fetch/interceptors/StatusFilter\";\n\n// Effect\u003cstring, DecodeError, Fetch\u003e\nconst program = Effect.gen(function* () {\n  const result = yield* Fetch.fetch(\"/users\");\n  return yield* Result.text(res);\n});\n\nconst interceptors = Interceptor.empty().pipe(\n  Interceptor.add(BaseURL(baseURL)),\n  Interceptor.add(StatusOK) // Effect\u003cResponse, StatusError, Fetch\u003e\n);\n\nconst interceptor = Interceptor.provide(\n  Interceptor.make(interceptors),\n  Adapter.fetch\n);\n\nconst adapter = Fetch.effect(interceptor);\n\n// Interceptors errors get carried over into the final computation type.\n// Unlike other HTTP libraries, we don't loose type information\n\n// Effect\u003cstring, DecodeError | StatusError, Fetch\u003e\nconst result = Effect.provide(program, adapter);\n```\n\n[more examples](/test)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshamaju%2Feffect-fetch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoshamaju%2Feffect-fetch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshamaju%2Feffect-fetch/lists"}