{"id":15937649,"url":"https://github.com/easywebapp/koajax","last_synced_at":"2026-04-02T12:04:52.905Z","repository":{"id":71648438,"uuid":"224000829","full_name":"EasyWebApp/KoAJAX","owner":"EasyWebApp","description":"HTTP Client based on Koa-like middlewares","archived":false,"fork":false,"pushed_at":"2024-10-28T17:11:06.000Z","size":510,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-28T18:42:53.613Z","etag":null,"topics":["ajax","client","http","koa","middleware","request"],"latest_commit_sha":null,"homepage":"https://web-cell.dev/KoAJAX/","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/EasyWebApp.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":"2019-11-25T17:07:57.000Z","updated_at":"2024-10-28T17:08:16.000Z","dependencies_parsed_at":null,"dependency_job_id":"87ec80db-be0f-47b1-98ea-7bd59f2d876b","html_url":"https://github.com/EasyWebApp/KoAJAX","commit_stats":null,"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyWebApp%2FKoAJAX","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyWebApp%2FKoAJAX/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyWebApp%2FKoAJAX/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyWebApp%2FKoAJAX/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EasyWebApp","download_url":"https://codeload.github.com/EasyWebApp/KoAJAX/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222047322,"owners_count":16922184,"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","client","http","koa","middleware","request"],"created_at":"2024-10-07T05:04:25.580Z","updated_at":"2026-04-02T12:04:52.897Z","avatar_url":"https://github.com/EasyWebApp.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# KoAJAX\n\n**HTTP Client** based on [Koa-like middlewares][1]\n\n[![NPM Dependency](https://img.shields.io/librariesio/github/EasyWebApp/KoAJAX.svg)][2]\n[![CI \u0026 CD](https://github.com/EasyWebApp/KoAJAX/actions/workflows/main.yml/badge.svg)][3]\n[![](https://data.jsdelivr.com/v1/package/npm/koajax/badge?style=rounded)][4]\n\n[![NPM](https://nodei.co/npm/koajax.png?downloads=true\u0026downloadRank=true\u0026stars=true)][5]\n\n## Feature\n\n### Request Body\n\nAutomatic Serialized types:\n\n1. Pure text: `string`\n2. Form encoding: `URLSearchParams`, `FormData`\n3. DOM object: `Node`\n4. JSON object: `Object`\n5. Binary data: `Blob`, `ArrayBuffer`, TypedArray, `DataView`\n6. Stream object: `ReadableStream`\n\n### Response Body\n\nAutomatic Parsed type:\n\n1. HTML/XML: `Document`\n2. JSON: `Object`\n3. Binary data: `ArrayBuffer`\n\n## Usage\n\n### Browser\n\n#### Installation\n\n```powershell\nnpm install koajax\n```\n\n#### `index.html`\n\n```html\n\u003chead\u003e\n    \u003cscript src=\"https://polyfill.web-cell.dev/feature/Regenerator.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"https://polyfill.web-cell.dev/feature/ECMAScript.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"https://polyfill.web-cell.dev/feature/TextEncoder.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"https://polyfill.web-cell.dev/feature/AbortController.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"https://polyfill.web-cell.dev/feature/Stream.js\"\u003e\u003c/script\u003e\n\u003c/head\u003e\n```\n\n### Node.js\n\n#### Installation\n\n```powershell\nnpm install koajax core-js jsdom\n```\n\n#### `index.ts`\n\n```javascript\nimport { polyfill } from 'koajax/source/polyfill';\n\nimport { HTTPClient } from 'koajax';\n\nconst origin = 'https://your-target-origin.com';\n\npolyfill(origin).then(() =\u003e {\n    const client = new HTTPClient({\n        baseURI: `${origin}/api`,\n        responseType: 'json'\n    });\n    const { body } = await client.get('test/interface');\n\n    console.log(body);\n});\n```\n\n#### Execution\n\n```powershell\nnpx tsx index.ts\n```\n\n### Non-polyfillable runtimes\n\n#### Taro (Mini Program, Open Harmony, etc.)\n\n##### 1. Install Polyfill\n\n```shell\nnpm install event-target-shim taro-fetch-polyfill\n```\n\n##### 2. Inject Runtime\n\nFollowing Example comes from https://github.com/idea2app/Taro-Vant-MobX-ts/blob/70f33be5b2365b8126ed93663905329eae25fbf0/src/store/service.ts\n\n```typescript\nimport { Event, EventTarget } from 'event-target-shim';\nimport { defaultHTTPRuntime, HTTPToolkit } from 'koajax';\nimport { Blob, Headers, ReadableStream, fetch } from 'taro-fetch-polyfill';\n\nconst { request } = new HTTPToolkit({\n    ...defaultHTTPRuntime,\n    Event: Event as typeof globalThis.Event,\n    EventTarget: EventTarget as typeof globalThis.EventTarget,\n    Headers,\n    Blob,\n    ReadableStream,\n    fetch: fetch as typeof globalThis.fetch\n});\n\nexport const httpClient = new HTTPClient({ baseRequest: request });\n```\n\n## Example\n\n### RESTful API with Token-based Authorization\n\n```javascript\nimport { HTTPClient } from 'koajax';\n\nvar token = '';\n\nexport const client = new HTTPClient().use(\n    async ({ request: { method, path, headers }, response }, next) =\u003e {\n        if (token) headers['Authorization'] = 'token ' + token;\n\n        await next();\n\n        if (method === 'POST' \u0026\u0026 path.startsWith('/session'))\n            token = response.headers.Token;\n    }\n);\n\nclient.get('/path/to/your/API').then(console.log);\n```\n\n### Up/Download files\n\n#### Single HTTP request based on XMLHTTPRequest `progress` events\n\n(based on [Async Generator][6])\n\n```javascript\nimport { request } from 'koajax';\n\ndocument.querySelector('input[type=\"file\"]').onchange = async ({\n    target: { files }\n}) =\u003e {\n    for (const file of files) {\n        const { upload, download, response } = request({\n            method: 'POST',\n            path: '/files',\n            body: file,\n            responseType: 'json'\n        });\n\n        for await (const { loaded } of upload)\n            console.log(`Upload ${file.name} : ${(loaded / file.size) * 100}%`);\n\n        const { body } = await response;\n\n        console.log(`Upload ${file.name} : ${body.url}`);\n    }\n};\n```\n\n#### Single HTTP request based on Fetch `duplex` streams\n\n\u003e This experimental feature has [some limitations][7].\n\n```diff\n-import { request } from 'koajax';\n+import { requestFetch } from 'koajax';\n\ndocument.querySelector('input[type=\"file\"]').onchange = async ({\n    target: { files }\n}) =\u003e {\n    for (const file of files) {\n-        const { upload, download, response } = request({\n+        const { upload, download, response } = requestFetch({\n            method: 'POST',\n            path: '/files',\n+            headers: {\n+                'Content-Type': file.type,\n+                'Content-Length': file.size + ''\n+            },\n-            body: file,\n+            body: file.stream(),\n            responseType: 'json'\n        });\n\n        for await (const { loaded } of upload)\n            console.log(`Upload ${file.name} : ${(loaded / file.size) * 100}%`);\n\n        const { body } = await response;\n\n        console.log(`Upload ${file.name} : ${body.url}`);\n    }\n};\n```\n\n#### Multiple HTTP requests based on `Range` header\n\n```powershell\nnpm i native-file-system-adapter  # Web standard API polyfill\n```\n\n```javascript\nimport { showSaveFilePicker } from 'native-file-system-adapter';\nimport { HTTPClient } from 'koajax';\n\nconst bufferClient = new HTTPClient({ responseType: 'arraybuffer' });\n\ndocument.querySelector('#download').onclick = async () =\u003e {\n    const fileURL = 'https://your.server/with/Range/header/supported/file.zip';\n    const suggestedName = new URL(fileURL).pathname.split('/').pop();\n\n    const fileHandle = await showSaveFilePicker({ suggestedName });\n    const writer = await fileHandle.createWritable(),\n        stream = bufferClient.download(fileURL);\n\n    try {\n        for await (const { total, loaded, percent, buffer } of stream) {\n            await writer.write(buffer);\n\n            console.table({ total, loaded, percent });\n        }\n        window.alert(`File ${fileHandle.name} downloaded successfully!`);\n    } finally {\n        await writer.close();\n    }\n};\n```\n\n### Global Error fallback\n\n```powershell\nnpm install browser-unhandled-rejection  # Web standard API polyfill\n```\n\n```javascript\nimport { auto } from 'browser-unhandled-rejection';\nimport { HTTPError } from 'koajax';\n\nauto();\n\nwindow.addEventListener('unhandledrejection', ({ reason }) =\u003e {\n    if (!(reason instanceof HTTPError)) return;\n\n    const { message } = reason.response.body;\n\n    if (message) window.alert(message);\n});\n```\n\n### Read Files\n\n(based on [Async Generator][6])\n\n```javascript\nimport { readAs } from 'koajax';\n\ndocument.querySelector('input[type=\"file\"]').onchange = async ({\n    target: { files }\n}) =\u003e {\n    for (const file of files) {\n        const { progress, result } = readAs(file, 'dataURL');\n\n        for await (const { loaded } of progress)\n            console.log(\n                `Loading ${file.name} : ${(loaded / file.size) * 100}%`\n            );\n\n        const URI = await result;\n\n        console.log(`Loaded ${file.name} : ${URI}`);\n    }\n};\n```\n\n[1]: https://github.com/koajs/koa#middleware\n[2]: https://libraries.io/npm/koajax\n[3]: https://github.com/EasyWebApp/KoAJAX/actions/workflows/main.yml\n[4]: https://www.jsdelivr.com/package/npm/koajax\n[5]: https://npm.im/koajax/\n[6]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of#Iterating_over_async_generators\n[7]: https://developer.chrome.com/docs/capabilities/web-apis/fetch-streaming-requests#restrictions\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasywebapp%2Fkoajax","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feasywebapp%2Fkoajax","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasywebapp%2Fkoajax/lists"}