{"id":48207,"library":"itty-fetcher","title":"itty-fetcher","description":"itty-fetcher is an ultra-compact (~650 bytes) typed wrapper around the native Fetch API, designed to eliminate boilerplate such as manually setting Content-Type headers, JSON encoding/decoding, and error handling. Version 1.0.10 is the latest stable release, maintained by the author of itty-router. It shifts the final response parsing, method/body handling, and base URL into a small, chainable, proxy-based interface. Differentiators include TypeScript generics for request/response types, composable response transforms via after hooks, and a runtime-minifiable snippet that fits in a tweet. The library is ESM-only and ships with TypeScript definitions.","status":"active","version":"1.0.10","language":"javascript","source_language":"en","source_url":"https://github.com/kwhitley/itty-fetcher","tags":["javascript","fetch","api","composable","tiny","simple","json","typescript"],"install":[{"cmd":"npm install itty-fetcher","lang":"bash","label":"npm"},{"cmd":"yarn add itty-fetcher","lang":"bash","label":"yarn"},{"cmd":"pnpm add itty-fetcher","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"ESM-only; named export. Cannot be imported as default or via require().","wrong":"import fetcher from 'itty-fetcher'","symbol":"fetcher","correct":"import { fetcher } from 'itty-fetcher'"},{"note":"Type import for TypeScript; Fetcher is the type of the returned proxy object.","wrong":"import { fetcher as Fetcher } from 'itty-fetcher'","symbol":"Fetcher","correct":"import type { Fetcher } from 'itty-fetcher'"},{"note":"The inline snippet is for environments without module support (e.g., plain <script> tags).","wrong":"Attempting to import { fetcher } from 'itty-fetcher' in a non-module script","symbol":"fetcher (snippet copy)","correct":"Copy the minified snippet from README directly"}],"quickstart":{"code":"import { fetcher } from 'itty-fetcher'\n\nconst api = fetcher('https://api.example.com', {\n  headers: { 'Authorization': `Bearer ${process.env.API_KEY ?? ''}` },\n  after: [\n    (response) => {\n      console.log('Request to', response.url, 'status:', response.status)\n      return response\n    }\n  ]\n})\n\n// GET request with typed response\ninterface User {\n  id: number\n  name: string\n}\n\nasync function fetchUser() {\n  const user = await api.get<User>('/users/1')\n  console.log(user.name)\n  return user\n}\n\n// POST request with typed request and response\ninterface CreateUserInput {\n  name: string\n}\n\nasync function createUser() {\n  const newUser = await api.post<CreateUserInput, User>('/users', { name: 'Alice' })\n  console.log('Created user:', newUser.id)\n  return newUser\n}","lang":"typescript","description":"Creates a reusable fetcher with base URL, headers, and response hook, then demonstrates typed GET and POST calls."},"warnings":[{"fix":"If you need different base URLs or headers, create separate fetcher instances.","message":"The fetcher() function with no arguments returns a new proxy. Subsequent calls to .get() etc. on the same proxy always use the same options provided at creation.","severity":"gotcha","affected_versions":">=0.0.0"},{"fix":"Only use after hooks for logging or transformation; avoid throwing in them.","message":"The after hooks run on every response, including error responses. If you throw inside an after hook, it will override the original error.","severity":"gotcha","affected_versions":">=0.0.0"},{"fix":"Set parse option to 'text' or 'blob' for non-JSON responses: api.get('/data.txt', { parse: 'text' })","message":"By default, the library automatically parses the response as JSON. If the response is not JSON, it will throw a parse error.","severity":"gotcha","affected_versions":">=0.0.0"}],"env_vars":null,"search_vec":"'1.0.10':39 '650':12 'api':20,109 'around':16 'author':48 'base':62,70 'boilerpl':24 'byte':13 'chainabl':67 'compact':11 'compos':79,110 'content':30 'content-typ':29 'definit':106 'design':21 'differenti':72 'elimin':23 'encoding/decoding':34 'error':36 'esm':100 'esm-on':99 'fetch':19,108 'fetcher':3,6 'final':56 'fit':92 'generic':75 'handl':37,60 'header':32 'hook':84 'includ':73 'interfac':71 'itti':2,5,51 'itty-fetch':1,4 'itty-rout':50 'javascript':107 'json':33,113 'latest':42 'librari':97 'maintain':45 'manual':27 'method/body':59 'minifi':89 'nativ':18 'pars':58 'proxi':69 'proxy-bas':68 'releas':44 'request/response':77 'respons':57,80 'router':52 'runtim':88 'runtime-minifi':87 'set':28 'shift':54 'ship':103 'simpl':112 'small':66 'snippet':90 'stabl':43 'tini':111 'transform':81 'tweet':95 'type':14,31,78 'typescript':74,105,114 'ultra':10 'ultra-compact':9 'url':63 'version':38 'via':82 'wrapper':15","created_at":"2026-06-07T16:55:26.791126+00:00","updated_at":"2026-06-07T16:55:26.791126+00:00","problems":[{"fix":"Specify the correct parse type: await api.get('/text', { parse: 'text' })","cause":"Response is not JSON but default parse mode is JSON (parse: 'json').","error":"SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data"},{"fix":"Ensure the snippet is correctly copied (the minified snippet handles this). If using import, use fetcher({}) or fetcher(base, options).","cause":"Using fetcher() with no arguments but without default parameter handling.","error":"TypeError: Cannot use 'in' operator to search for 'headers' in undefined"}],"ecosystem":"npm","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"cli_name":null,"cli_version":null,"type":"library","homepage":"https://github.com/kwhitley/itty-fetcher#readme","github":"https://github.com/kwhitley/itty-fetcher","docs":null,"changelog":null,"pypi":null,"npm":"itty-fetcher","openapi_spec":null,"status_page":null,"smithery":null,"categories":["devops"],"base_url":null,"auth_type":null,"provenance":{"verified_status":null,"verified_at":null,"last_verified":"2026-06-07","next_check":"2026-09-05","install_tag":null}}