{"id":19281264,"url":"https://github.com/zouloux/fetcher","last_synced_at":"2026-06-15T08:31:52.927Z","repository":{"id":63891968,"uuid":"513842622","full_name":"zouloux/fetcher","owner":"zouloux","description":null,"archived":false,"fork":false,"pushed_at":"2023-09-28T07:55:26.000Z","size":74,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-17T01:23:50.619Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/zouloux.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2022-07-14T09:42:12.000Z","updated_at":"2022-12-15T00:27:13.000Z","dependencies_parsed_at":"2024-11-09T21:33:59.172Z","dependency_job_id":null,"html_url":"https://github.com/zouloux/fetcher","commit_stats":{"total_commits":9,"total_committers":1,"mean_commits":9.0,"dds":0.0,"last_synced_commit":"088efa27bb2188b69be9c40898fa1e94e4a2db65"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/zouloux/fetcher","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zouloux%2Ffetcher","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zouloux%2Ffetcher/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zouloux%2Ffetcher/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zouloux%2Ffetcher/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zouloux","download_url":"https://codeload.github.com/zouloux/fetcher/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zouloux%2Ffetcher/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34355157,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-11-09T21:22:10.766Z","updated_at":"2026-06-15T08:31:52.875Z","avatar_url":"https://github.com/zouloux.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fetcher\n\nFetcher is a ![](./bits/index.es2017.min.js.svg) helper to build pre-configured fetch functions with strict type.\n\n## Quick example\n\n```typescript\nimport { createFetcher } from \"./fetcher\";\n\n// A random user object\ninterface IUser {\n    id\t:number\n    name:string\n}\n\n// Create a new fetcher, usable everywhere in your project\nconst fetchUser = createFetcher\u003c[number], IUser\u003e({\n    base: '/api/1.0/',\n    buildURI (request, args) {\n        return `get-user/${args[0]}`\n    }\n})\n\n// Somewhere else in your code ...\nconst user = await fetchUser( 12 )\n// Executed : fetch('/api/1.0/get-user/12')\nconsole.log(user.name) // Jean-Mi\n```\n\n## Example with complex types :\n\n```typescript\n// RestFetcher request type descriptors\ntype RestFetcher = {\n    // Arguments of the fetcher\n    args: ['get-user', { id:number }],\n    // And its response\n    response: IUser\n} | {\n    // Other example with one argument as a string\n    args: [`get-user/${number}`],\n    response: IUser\n}\n\n// Create the fetcher and pass the type descriptors\nconst restFetcher = createFetcher\u003cRestFetcher[\"args\"], RestFetcher[\"response\"]\u003e({\n    // Prepend before each fetch uri\n    base: '/api/1.0/',\n    responseType: 'json',\n    // Will build the URI\n    buildURI ( request, args ) {\n        return args[0] + '/' + args[1].id \n    }\n})\n\n// Get object of ID 12 following first descriptor\nconst result1 = await restFetcher('get-user', { id: 12 })\n// Executed : fetch('/api/1.0/get-user/12')\nconsole.log( result1.name ) // Jean-Mi \n\n// Get object of ID 14 following second descriptor\nconst result2 = await restFetcher('get-user/14')\n// Executed : fetch('/api/1.0/get-user/14')\nconsole.log( result2.name ) // Albert\n\n// 🚫 Typescript will reject those\nconst result3 = await restFetcher('get-a-user', { id: 12 }) // wrong first argument\nconst result4 = await restFetcher('get-user/') // missing id in string or as object\nconst result5 = await restFetcher('get-user/turlututu') // not a number\n```\n\n## API / Usage\n\n```typescript\nconst myThunkFetcher = createFetcher({\n    base: string,\t\t\t// base prepend to the uri\n    request: RequestInit, \t// the base fetch request init object\n    // Build the fetch URI\n    // Request here is the request object sent to fetch\n    // Args is the argument array sent by the thunk function ['Arg1', 'Arg2']\n    buildURI ( request, args ) {\n        return `/api/1.0/${args[0]}`\n    },\n    // Build the GET parameters\n    buildGet ( request, args ) {\n        // Can return string\n        return \"a=12;b=\"+args[1]\n        // Can return 1 level deep record\n        return {\n            a: 12,\n            b: args[1]\n        }\n    },\n    // Build the body\n    buildbody ( request, args ) {\n        // Can return a string for rest by example\n        return JSON.stringify( args[1] )\n        // Can return form data for multipart\n        // $myForm contains inputs and files\n        return new FormData( $myForm )\n        // Can return 1 level deep record\n        return {\n            a: 12,\n            b: args[1]\n        }\n    },\n    // Available response types ( default is json )\n    responseType : \"text\" | \"json\" | \"dom\" | \"blob\",\n    // Will filter the response given from the server\n    filterResponse ( response, args ) {\n        // If http is successful but server returned an unsuccessful content\n        // Throw response so the fetch will go into error state\n        if ( !response.success )\n            throw response\n        // Alter response\n        delete remove.success\n        remove.value = randomGlobalValue\n        return resposne\n    },\n    // Custom error handler\n    // If implemented, resolve or reject need to be called !\n    errorHandler ( error, args, resolve, reject ) {\n        // ... either resolve or reject with custom behavior\n        // Error can be FetcherError in case of HTTP or DNS error\n        // FetcherError has a .response property which point to the fetch response. \n    },\n    // Shorthand : If errorHandler is set to false, no error will be thrown,\n    // and promise will be resolved with null in case of error\n    errorHandler: false,\n    // Custom check if fetch response is OK\n    // Here response is right after fetch ( @see Response )\n    // By default, will check if response.ok is true\n    isResponseOK: response =\u003e response.ok\n})\n\n// ...\nawait myThunkFetcher('Arg1', 'Arg2')\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzouloux%2Ffetcher","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzouloux%2Ffetcher","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzouloux%2Ffetcher/lists"}