{"id":19453257,"url":"https://github.com/egamagz/pretch","last_synced_at":"2025-07-11T11:37:17.420Z","repository":{"id":258677207,"uuid":"864785707","full_name":"EGAMAGZ/pretch","owner":"EGAMAGZ","description":"A lightweight and flexible fetch enhancement library that works with vanilla JavaScript, React, and Preact.","archived":false,"fork":false,"pushed_at":"2025-04-09T23:14:34.000Z","size":319,"stargazers_count":11,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-10T00:24:55.352Z","etag":null,"topics":["bun","deno","fetch","nodejs","preact","react","vanilla-javascript"],"latest_commit_sha":null,"homepage":"https://jsr.io/@pretch","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EGAMAGZ.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2024-09-29T06:44:58.000Z","updated_at":"2025-03-22T23:41:23.000Z","dependencies_parsed_at":"2024-11-10T06:17:00.132Z","dependency_job_id":"cb817901-d937-4e59-b637-fa65773d0804","html_url":"https://github.com/EGAMAGZ/pretch","commit_stats":null,"previous_names":["egamagz/pretch"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EGAMAGZ%2Fpretch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EGAMAGZ%2Fpretch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EGAMAGZ%2Fpretch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EGAMAGZ%2Fpretch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EGAMAGZ","download_url":"https://codeload.github.com/EGAMAGZ/pretch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248976299,"owners_count":21192368,"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":["bun","deno","fetch","nodejs","preact","react","vanilla-javascript"],"created_at":"2024-11-10T17:03:12.042Z","updated_at":"2025-04-14T23:23:35.897Z","avatar_url":"https://github.com/EGAMAGZ.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pretch\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://jsr.io/@pretch\"\u003e\n    \u003cimg src=\"./docs/images/logo.png\" width=\"200\" height=\"auto\" alt=\"Hono\"/\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\nA lightweight and flexible fetch enhancement library that works with vanilla\nJavaScript, React, and Preact.\n\n[![JSR Scope](https://jsr.io/badges/@pretch)](https://jsr.io/@pretch)\n![GitHub License](https://img.shields.io/github/license/egamagz/pretch)\n![GitHub Release](https://img.shields.io/github/v/release/egamagz/pretch)\n\nCheck the [Documentation](https://jsr.io/@pretch) in JSR\n\n## Features\n\n- 🌐 Universal Compatibility – Seamlessly runs in all JavaScript environments,\n  including Node.js, Bun, Deno, and browsers.\n- ⚛️ Tailored for React \u0026 Preact – Enjoy dedicated hooks with full-feature\n  integration for both frameworks.\n- 🔧 Endlessly Customizable – Design custom fetch functions tailored to your\n  unique requirements.\n- 📝 TypeScript Native – Built-in TypeScript support ensures a flawless\n  developer experience.\n- 🛠 Powerful Middleware System – Leverage built-in middleware or create your own\n  for extended functionality.\n- 📦 Web API Driven – Crafted with a focus on modern Web APIs for seamless\n  integration.\n\n## Packages\n\n- `@pretch/core` - Core functionality and middleware system\n- `@pretch/react` - React hooks integration\n- `@pretch/preact` - Preact hooks integration\n\n## Usage\n\n### Core (Vanilla Javascript) - @pretch/core\n\nIn the nexts examples, fetch is enhaced with a middleware that will be\nautomatically add default headers to every request:\n\nCreate a custom fetch with behaviour enhaced through middleware and a base URL\n\n```ts\nimport pretch from \"@pretch/core\";\nimport { applyMiddleware, defaultHeaders } from \"@pretch/core/middleware\";\n\nconst customFetch = pretch(\n  \"https://jsonplaceholder.typicode.com/todos/\",\n  applyMiddleware(\n    defaultHeaders({\n      \"Content-Type\": \"application/json; charset=UTF-8\",\n    }, {\n      strategy: \"append\",\n    }),\n  ),\n);\n\nconst getResponse = await customFetch.get(\"/1\");\n\nconst createdTodo = await getResponse.json();\n\n// The following request will keep the enhanced behaviour of adding default headers\nconst putResponse = await customFetch.put(\"/1\", {\n  body: JSON.stringify({\n    title: \"Updated todo\",\n    body: \"Same task\",\n    userId: 1,\n  }),\n});\n\nconst todoUpdated = await putResponse.json();\n```\n\nCreate a custom fetch with behaviour enhaced through middleware to query\ndifferent urls\n\n```ts\nimport pretch from \"@pretch/core\";\nimport { applyMiddleware, defaultHeaders } from \"@pretch/core/middleware\";\n\nconst customFetch = pretch(\n  applyMiddleware(\n    defaultHeaders({\n      \"Content-Type\": \"application/json; charset=UTF-8\",\n    }, {\n      strategy: \"append\",\n    }),\n  ),\n);\n\nconst firstResponse = await customFetch(\"https://example.com/api/task\");\n\nconst todo = await firstResponse.json();\n\nconst secondResponse = await customFetch(\n  \"https://otherexample.com/api/auth/sing-in\",\n);\n\nconst user = await secondResponse.json();\n```\n\n## Built-in middlewares\n\nPretch provides a built-in enhancer to apply middlewares on each request\n\n### Validate Status\n\n```ts\nimport pretch from \"@pretch/core\";\nimport { applyMiddleware, validateStatus } from \"@pretch/core/middleware\";\n\nconst customFetch = pretch(\n  applyMiddleware(\n    validateStatus({\n      validate: (status) =\u003e 200 \u003c= status \u0026\u0026 status \u003c= 399,\n      errorFactory: (status, request, response) =\u003e\n        new Error(`Error. Status code: ${status}`),\n      shouldCancelBody: true,\n    }),\n  ),\n);\n```\n\n### Retry\n\n```ts\nimport pretch from \"@pretch/core\";\nimport { applyMiddleware, retry } from \"@pretch/core/middleware\";\n\nconst customFetch = pretch(\n  applyMiddleware(\n    retry({\n      maxRetries: 2,\n      delay: 1_500,\n    }),\n  ),\n);\n```\n\n### Default Headers\n\n```ts\nimport pretch from \"@pretch/core\";\nimport { applyMiddleware, defaultHeaders } from \"@pretch/core/middleware\";\n\nconst customFetch = pretch(\n  applyMiddleware(\n    defaultHeaders({\n      \"Content-Type\": \"application/json; charset=UTF-8\",\n    }, {\n      strategy: \"set\", // Optional, by default the headers appended\n    }),\n  ),\n);\n```\n\n### Authorization\n\n```ts\nimport pretch from \"@pretch/core\";\nimport { applyMiddleware, authorization } from \"@pretch/core/middleware\";\n\nconst customFetch = pretch(\n  applyMiddleware(\n    authorization(\n      \"123456789abcdef\",\n      \"bearer\",\n      {\n        shouldApplyToken: (request: Request) =\u003e\n          new URL(request.url).pathname.startsWith(\"/api/\"),\n      },\n    ),\n  ),\n);\n```\n\n### Logging\n\n```ts\nimport pretch from \"@pretch/core\";\nimport {\n  applyMiddleware,\n  type ErrorLogData,\n  logging,\n  type RequestLogData,\n  type ResponseLogData,\n} from \"@pretch/core/middleware\";\n\nconst customFetch = pretch(\n  applyMiddleware(\n    logging({\n      onRequest: async ({ request }: RequestLogData) =\u003e {\n        console.log(`Starting request to ${request.url}`);\n      },\n      onResponse: async ({ response }: ResponseLogData) =\u003e {\n        console.log(`Received response with status ${response.status}`);\n      },\n      onCatch: async ({ error }: ErrorLogData) =\u003e {\n        console.error(`Request failed:`, error);\n      },\n    }),\n  ),\n);\n```\n\n### Proxy\n\n```ts\nimport pretch from \"@pretch/core\";\nimport { applyMiddleware, proxy } from \"@pretch/core/middleware\";\n\nconst customFetch = pretch(\n  applyMiddleware(\n    proxy(\n      \"/api\", // Forward all requests starting with /api\n      \"https://api.example.com\",\n      {\n        pathRewrite: (path: string) =\u003e path.replace(/^\\/api/, \"\"), // Remove /api prefix\n      },\n    ),\n  ),\n);\n```\n\n## React integration(@pretch/react) and Preact integration(@pretch/preact)\n\nThe React and Preact integration delivers powerful hooks for both automatic and\nmanual fetching, complete with built-in state management. Both packages share a\nunified API and identical features, with the only difference being the package\nsource for importing the hooks.\n\nKey Features of the Hooks:\n\n- 🔄 Loading \u0026 Error State Management – Effortlessly track request states with\n  built-in tools.\n- 🛡 Type-Safe Response Handling – Enjoy confidence in your data with robust\n  TypeScript support.\n- ⚙️ Request Enhancement – Easily customize and optimize fetch requests to meet\n  your needs.\n- 🛠 Seamless @pretch/core Integration – Fully compatible with middlewares,\n  enhancers, and other advanced features provided by the @pretch/core package.\n\n### Fetching with `useFetch`\n\n`useFetch` automatically fetches the data when the component mounts. You can\nrefetch the data when the `refetch` function is called.\n\n```tsx\nimport { useFetch } from \"@pretch/react\";\n\nfunction MyComponent() {\n  const { data, loading, error, refetch } = useFetch(\n    \"https://api.example.com/todos/1\",\n  );\n\n  const handleClick = () =\u003e {\n    refetch();\n  };\n\n  return (\n    \u003cdiv\u003e\n      {loading ? \"Loading...\" : \"Data: \" + JSON.stringify(data)}\n      {error \u0026\u0026 \u003cp\u003eError: {error.message}\u003c/p\u003e}\n      \u003cbutton onClick={handleClick} disabled={loading}\u003eRefresh\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Fetching with `useLazyFetch`\n\n`useLazyFetch` fetches the data manually. You can trigger the fetch with the\n`fetchData` function.\n\n```tsx\nimport { useLazyFetch } from \"@pretch/react\";\n\nfunction MyComponent() {\n  const { data, loading, error, fetchData } = useLazyFetch({\n    url: \"https://api.example.com/todos/1\",\n  });\n\n  const handleClick = () =\u003e {\n    fetchData({\n      newOptions: {\n        method: \"POST\",\n        body: JSON.stringify({ title: \"New Todo\" }),\n      },\n    });\n  };\n\n  return (\n    \u003cdiv\u003e\n      {loading ? \"Loading...\" : \"Data: \" + JSON.stringify(data)}\n      {error \u0026\u0026 \u003cp\u003eError: {error.message}\u003c/p\u003e}\n      \u003cbutton onClick={handleClick}\u003eCreate Todo\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Fetching with `useQuery`\n\nA hook that provides a set of type-safe HTTP method functions (GET, POST, PUT,\nPATCH, DELETE, HEAD, OPTIONS) for making requests to a base URL. It includes\nbuilt-in state management using signals to track loading states and errors.\n\n```tsx\nimport { useQuery } from \"@pretch/react\";\n\ninterface Todo {\n  id: number;\n  title: string;\n  completed: boolean;\n}\n\nfunction TodoExample() {\n  const { get, post } = useQuery(\"https://api.example.com\");\n\n  const handleFetch = async () =\u003e {\n    const { data, loading, error } = await get\u003cTodo\u003e(\"/todos/1\");\n\n    if (error) {\n      console.error(\"Failed to fetch:\", error);\n      return;\n    }\n\n    if (data) {\n      console.log(\"Todo:\", data.title);\n    }\n  };\n\n  const handleCreate = async () =\u003e {\n    const { data, error } = await post\u003cTodo\u003e(\"/todos\", {\n      body: JSON.stringify({\n        title: \"New Todo\",\n        completed: false,\n      }),\n    });\n\n    if (data) {\n      console.log(\"Created todo:\", data);\n    }\n  };\n\n  return (\n    \u003cdiv\u003e\n      \u003cbutton onClick={handleFetch}\u003eFetch Todo\u003c/button\u003e\n      \u003cbutton onClick={handleCreate}\u003eCreate Todo\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nThe hook provides all standard HTTP methods (`get`, `post`, `put`, `patch`,\n`delete`, `head`, `options`) that return a promise containing:\n\n- `data`: The parsed response data\n- `loading`: Boolean indicating if request is in progress\n- `error`: Error object if request failed (or null)\n\nEach method supports URL parameters and request options, with full TypeScript\nsupport for response types.\n\n### Enhanced the fetching of `useFetch`, `useLazyFetch` and `useQuery`\n\nThe hook supports request enhancement through enhancer functions for customizing\nrequest behavior:\n\n**Custom enhancer**: Implement your own enhancer function to modify the request\nbehavior before it is sent.\n\n```tsx\nimport type { Enhancer, Handler } from \"@pretch/core\";\nimport { useFetch } from \"@pretch/react\";\n\nfunction authHeaderEnhancer(handler: Handler) {\n  return async (request: Request) =\u003e {\n    const modifiedRequest = new Request(request, {\n      headers: {\n        ...request.headers,\n        \"Authorization\": \"Bearer my-token\",\n      },\n    });\n\n    return handler(modifiedRequest);\n  };\n}\n\nfunction MyComponent() {\n  const { data } = useFetch(\"https://example.com\", {\n    enhancer: authHeaderEnhancer,\n  });\n\n  return (\n    \u003cdiv\u003e\n      Data: {JSON.stringify(data)}\n    \u003c/div\u003e\n  );\n}\n```\n\n**Built-in middlewares**: Otherwise, Pretch provides a built-in enhancer to\napply middlewares on each request, including built-in middlewares.\n\n```tsx\nimport {\n  applyMiddleware,\n  authorization,\n  defaultHeaders,\n  retry,\n} from \"@pretch/core\";\n\nimport { useFetch, useLazyFetch, useQuery } from \"@precth/react\";\n\nfunction TodoList() {\n  const { data, loading, error, refetch } = useFetch(\n    \"https://api.example.com/todos/\",\n    {\n      enhancer: applyMiddleware(\n        retry({\n          maxRetries: 2,\n          delay: 500,\n        }),\n        authorization(\"your-token\", \"bearer\"),\n      ),\n    },\n  );\n\n  const handleClick = () =\u003e { refetch() };\n\n  return (\n    \u003cdiv\u003e\n      {loading ? \u003cspan\u003eLoading...\u003c/span\u003e : (\n        \u003cul\u003e\n          {data.map((todo) =\u003e {\n            \u003cli\u003e{todo.title}\u003c/li\u003e;\n          })}\n        \u003c/ul\u003e\n      )}\n      {error \u0026\u0026 \u003cp\u003eError: {error.message}\u003c/p\u003e}\n      \u003cbutton onClick={handleClick}\u003eRefresh\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n\nfunction CreateTodo() {\n  const {data, fetchData, error, loading} = useLazyFetch({\n    url: \"https://api.example.com/todos/\",\n    enhancer: applyMiddleware(\n      defaultHeaders({\n        \"Content-Type\": \"application/json; charset=UTF-8\",\n      }),\n    ),\n  });\n\n  const handleSubmit = async (event: SubmitEvent ) =\u003e {\n    event.preventDefault();\n    const formData = new FormData(event.target as HTMLFormElement);\n\n    fetchData({\n      newOptions: {\n        method: \"POST\",\n        body: JSON.stringify(Object.fromEntries(formData.entries()))\n      }\n    })\n  };\n\n  return (\n    \u003cform onSubmit={handleSubmit}\u003e\n      \u003cinput name=\"title\" \u003e\n      \u003cbutton\u003eCreate\u003c/button\u003e\n    \u003c/form\u003e\n  );\n}\n```\n\n## Why Pretch?\n\nStruggling to find a simple yet customizable fetching hook library for Preact, I\ncreated @pretch/preact, focusing on ease of use, minimal abstraction, and\nalignment with Web APIs. This evolved into @pretch/core, a versatile package for\nfetch customization with built-in middlewares and enhancers, later extended to\n@pretch/react and @pretch/preact for React and Preact integration.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## Credits\n\nCreated by [EGAMAGZ](https://github.com/EGAMAGZ)\n\n## License\n\nMIT License\n\n## TODO\n\n- [x] Create useQuery hook inspired on @tanstack/react-query and redux query\n- [ ] Develop and automatize tests for @pretch/preact and @pretch/react\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegamagz%2Fpretch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fegamagz%2Fpretch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegamagz%2Fpretch/lists"}