{"id":15486228,"url":"https://github.com/fakoua/soxa","last_synced_at":"2025-09-11T17:47:42.577Z","repository":{"id":62421557,"uuid":"229070297","full_name":"fakoua/soxa","owner":"fakoua","description":"Promise based HTTP client for the deno","archived":false,"fork":false,"pushed_at":"2020-09-16T16:02:53.000Z","size":157,"stargazers_count":35,"open_issues_count":1,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-08T05:53:47.984Z","etag":null,"topics":["cancellation","deno","http-clinet","intercept-requests","interceptors","javascript","promise","typescript"],"latest_commit_sha":null,"homepage":null,"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/fakoua.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-19T14:22:33.000Z","updated_at":"2023-06-19T02:05:32.000Z","dependencies_parsed_at":"2022-11-01T17:32:20.845Z","dependency_job_id":null,"html_url":"https://github.com/fakoua/soxa","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/fakoua/soxa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fakoua%2Fsoxa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fakoua%2Fsoxa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fakoua%2Fsoxa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fakoua%2Fsoxa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fakoua","download_url":"https://codeload.github.com/fakoua/soxa/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fakoua%2Fsoxa/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274681441,"owners_count":25330236,"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","status":"online","status_checked_at":"2025-09-11T02:00:13.660Z","response_time":74,"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":["cancellation","deno","http-clinet","intercept-requests","interceptors","javascript","promise","typescript"],"created_at":"2024-10-02T06:07:12.052Z","updated_at":"2025-09-11T17:47:42.513Z","avatar_url":"https://github.com/fakoua.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# soxa\r\n\r\n![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/fakoua/soxa?style=for-the-badge)\r\n![GitHub](https://img.shields.io/github/license/fakoua/soxa?style=for-the-badge)\r\n![GitHub last commit](https://img.shields.io/github/last-commit/fakoua/soxa?style=for-the-badge)\r\n![GitHub Workflow Status](https://img.shields.io/github/workflow/status/fakoua/soxa/Deno%20CI?style=for-the-badge)\r\n\r\n\r\n\r\nPromise based HTTP client for deno\r\n\r\n## Table of Contents\r\n\r\n  - [Features](#features)\r\n  - [Example](#example)\r\n  - [Config Defaults](#config-defaults)\r\n  - [Interceptors](#interceptors)\r\n  - [Handling Errors](#handling-errors)\r\n  - [Cancellation](#cancellation)\r\n  - [Using application/x-www-form-urlencoded format](#using-applicationx-www-form-urlencoded-format)\r\n  - [Credits](#credits)\r\n  - [License](#license)\r\n  \r\n## Features\r\n\r\n- Make [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) requests from deno\r\n- Supports the [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) API\r\n- Intercept request and response\r\n- Transform request and response data\r\n- Cancel requests\r\n- Automatic transforms for JSON data\r\n\r\n## Installation\r\n\r\nUsing deno:\r\n\r\n```ts\r\nimport { soxa } from 'https://deno.land/x/soxa/mod.ts'\r\n```\r\n\r\n## Example\r\n\r\nPerforming a `GET` request (Promise)\r\n\r\n```ts\r\nimport { soxa } from 'https://deno.land/x/soxa/mod.ts'\r\n\r\n// soxa.get(url, config)\r\n// soxa.head(url, config)\r\n// soxa.delete(url, config)\r\n\r\n// soxa.post(url, data, config)\r\n// soxa.put(url, data, config)\r\n// soxa.patch(url, data, config)\r\n\r\n\r\n//Example\r\n// Make a request for todos\r\nsoxa.get('https://jsonplaceholder.typicode.com/todos/1')\r\n  .then(function (response) {\r\n    // handle success\r\n    console.log(response.data);\r\n  })\r\n  .catch(function (error) {\r\n    // handle error\r\n    console.log(error);\r\n  })\r\n  .finally(function () {\r\n    // always executed\r\n  });\r\n```\r\n\r\nPerforming a `GET` request (Await/Async)\r\n\r\n```ts\r\nlet result = await soxa.get('https://jsonplaceholder.typicode.com/todos/1');\r\nconsole.log(result.data)\r\n```\r\n\r\nPerforming a `POST` request\r\n\r\n```ts\r\nlet response = await soxa.post('https://jsonplaceholder.typicode.com/posts', {\r\n                          \"title\": \"Hello Soxa\",\r\n                          \"id\": 14\r\n                      });\r\n//Note: data is passed with valid JSON format ( {\"key\": \"string-value\", \"key2\": int-value ...} )\r\n\r\n//OR you can send the data with the config object.\r\nlet response = await soxa.post('https://jsonplaceholder.typicode.com/posts', {}, {\r\n    headers: {'x-user': 'fakoua'},\r\n    data: {\r\n        \"title\":\"Hello Soxa\",\r\n        \"id\":14\r\n    }\r\n});\r\n```\r\n\r\n## URL Examples\r\n\r\n```ts\r\nawait soxa.get('http://example.com'); // http://example.com\r\nawait soxa.get('http://example.com', { params: { q: 'hello' } }); // http://example.com?q=hello\r\nawait soxa.get('http://example.com', { params: { q: 'hello', id: 12 } }); // http://example.com?q=hello\u0026id=12\r\n\r\nawait soxa.get('http://example.com/folder', { params: { q: 'hello' } }); // http://example.com/folder?q=hello\r\n\r\n//Note: if baseURL is set in the config, you only need to pass the /folder relative path.\r\nlet config = {\r\n  baseURL: 'http://example.com/',\r\n  params: {\r\n            q: 'hello'\r\n          }\r\n }\r\nawait soxa.get('/folder', config); // http://example.com/folder?q=hello\r\n```\r\n\r\n## Config\r\n\r\nThese are the available config options for making requests. Only the `url` is required. Requests will default to `GET` if `method` is not specified.\r\n\r\n```ts\r\n{\r\n  // `baseURL` will be prepended to `url` unless `url` is absolute.\r\n  // It can be convenient to set `baseURL` for an instance of soxa to pass relative URLs\r\n  // to methods of that instance.\r\n  baseURL: 'https://some-domain.com/api/',\r\n\r\n  // `transformRequest` allows changes to the request data before it is sent to the server\r\n  // This is only applicable for request methods 'PUT', 'POST', 'PATCH' and 'DELETE'\r\n  // The last function in the array must return a string or an instance of Buffer, ArrayBuffer,\r\n  // FormData or Stream\r\n  // You may modify the headers object.\r\n  transformRequest: [function (data, headers) {\r\n    // Do whatever you want to transform the data\r\n\r\n    return data;\r\n  }],\r\n\r\n  // `transformResponse` allows changes to the response data to be made before\r\n  // it is passed to then/catch\r\n  transformResponse: [function (data) {\r\n    // Do whatever you want to transform the data\r\n\r\n    return data;\r\n  }],\r\n\r\n  // `headers` are custom headers to be sent\r\n  headers: {'X-Requested-With': 'XMLHttpRequest'},\r\n\r\n  // `params` are the URL parameters to be sent with the request\r\n  // Must be a plain object or a URLSearchParams object\r\n  // Result:  [url]/?ID=12345\r\n  params: {\r\n    ID: 12345\r\n  },\r\n\r\n  // `paramsSerializer` is an optional function in charge of serializing `params`\r\n  // (e.g. http://api.jquery.com/jquery.param/)\r\n  paramsSerializer: function (params) {\r\n    return ...\r\n  },\r\n\r\n  // `data` is the data to be sent as the request body\r\n  // Only applicable for request methods 'PUT', 'POST', and 'PATCH'\r\n  // When no `transformRequest` is set, must be of one of the following types:\r\n  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams\r\n  // Browser only: FormData, File, Blob\r\n  data: {\r\n    firstName: 'Fred'\r\n  },\r\n  \r\n  // syntax alternative to send data into the body\r\n  // method post\r\n  // only the value is sent, not the key\r\n  data: 'Country=Brasil\u0026City=Belo Horizonte',\r\n\r\n  // `timeout` specifies the number of milliseconds before the request times out.\r\n  // If the request takes longer than `timeout`, the request will be aborted.\r\n  timeout: 1000, // default is `0` (no timeout)\r\n\r\n  // `withCredentials` indicates whether or not cross-site Access-Control requests\r\n  // should be made using credentials\r\n  withCredentials: false, // default\r\n\r\n  // `auth` indicates that HTTP Basic auth should be used, and supplies credentials.\r\n  // This will set an `Authorization` header, overwriting any existing\r\n  // `Authorization` custom headers you have set using `headers`.\r\n  // Please note that only HTTP Basic auth is configurable through this parameter.\r\n  // For Bearer tokens and such, use `Authorization` custom headers instead.\r\n  auth: {\r\n    username: 'sam',\r\n    password: 'pass'\r\n  }, //This will be transformed and added to header -\u003e \"Authorization\": \"Basic c2FtOnBhc3M=\"\r\n\r\n  // `responseType` indicates the type of data that the server will respond with\r\n  // options are: 'arraybuffer', 'document', 'json', 'text', 'stream'\r\n  //   browser only: 'blob'\r\n  responseType: 'json', // default\r\n\r\n  // `responseEncoding` indicates encoding to use for decoding responses\r\n  // Note: Ignored for `responseType` of 'stream' or client-side requests\r\n  responseEncoding: 'utf8', // default\r\n\r\n  // `onUploadProgress` allows handling of progress events for uploads\r\n  onUploadProgress: function (progressEvent) {\r\n    // Do whatever you want with the native progress event\r\n  },\r\n\r\n  // `onDownloadProgress` allows handling of progress events for downloads\r\n  onDownloadProgress: function (progressEvent) {\r\n    // Do whatever you want with the native progress event\r\n  },\r\n\r\n  // `maxContentLength` defines the max size of the http response content in bytes allowed\r\n  maxContentLength: 2000,\r\n\r\n  // `validateStatus` defines whether to resolve or reject the promise for a given\r\n  // HTTP response status code. If `validateStatus` returns `true` (or is set to `null`\r\n  // or `undefined`), the promise will be resolved; otherwise, the promise will be\r\n  // rejected.\r\n  validateStatus: function (status) {\r\n    return status \u003e= 200 \u0026\u0026 status \u003c 300; // default\r\n  },\r\n\r\n  // `maxRedirects` defines the maximum number of redirects to follow in node.js.\r\n  // If set to 0, no redirects will be followed.\r\n  maxRedirects: 5, // default\r\n\r\n  // `socketPath` defines a UNIX Socket to be used in node.js.\r\n  // e.g. '/var/run/docker.sock' to send requests to the docker daemon.\r\n  // Only either `socketPath` or `proxy` can be specified.\r\n  // If both are specified, `socketPath` is used.\r\n  socketPath: null, // default\r\n\r\n  // `cancelToken` specifies a cancel token that can be used to cancel the request\r\n  // (see Cancellation section below for details)\r\n  cancelToken: new CancelToken(function (cancel) {\r\n  })\r\n}\r\n\r\n//Example auth:\r\n\r\nlet config = {\r\n    auth: {\r\n        username: 'myUser',\r\n        password: 'myPassword'\r\n      }\r\n}\r\n\r\nsoxa.post(url, {} ,config)\r\n  .then(function (response) {\r\n    console.log(response);\r\n  })\r\n  .catch(function (error) {\r\n    console.log(error);\r\n  });\r\n```\r\n\r\n## Response Schema\r\n\r\nThe response for a request contains the following information.\r\n\r\n```ts\r\n{\r\n  // `data` is the response that was provided by the server\r\n  data: {},\r\n\r\n  // `status` is the HTTP status code from the server response\r\n  status: 200,\r\n\r\n  // `statusText` is the HTTP status message from the server response\r\n  statusText: 'OK',\r\n\r\n  // `headers` the headers that the server responded with\r\n  // All header names are lower cased\r\n  headers: {},\r\n\r\n  // `config` is the config that was provided to `soxa` for the request\r\n  config: {},\r\n\r\n  // `request` is the request that generated this response\r\n  // It is the last ClientRequest instance in node.js (in redirects)\r\n  // and an XMLHttpRequest instance in the browser\r\n  request: {}\r\n}\r\n```\r\n\r\nWhen using `then`, you will receive the response as follows:\r\n\r\n```ts\r\nsoxa.get('/user/12345')\r\n  .then(function (response) {\r\n    console.log(response.data);\r\n    console.log(response.status);\r\n    console.log(response.statusText);\r\n    console.log(response.headers);\r\n    console.log(response.config);\r\n  });\r\n```\r\n\r\nWhen using `catch`, or passing a [rejection callback](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then) as second parameter of `then`, the response will be available through the `error` object as explained in the [Handling Errors](#handling-errors) section.\r\n\r\n## Config Defaults\r\n\r\nYou can specify config defaults that will be applied to every request.\r\n\r\n### Global soxa defaults\r\n\r\n```ts\r\nsoxa.defaults.baseURL = 'https://api.example.com';\r\nsoxa.defaults.headers.common['Authorization'] = AUTH_TOKEN;\r\nsoxa.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';\r\n```\r\n\r\n## Interceptors\r\n\r\nYou can intercept requests or responses before they are handled by `then` or `catch`.\r\n\r\n```ts\r\n// Add a request interceptor\r\nsoxa.interceptors.request.use(function (config) {\r\n    // Do something before request is sent\r\n    return config;\r\n  }, function (error) {\r\n    // Do something with request error\r\n    return Promise.reject(error);\r\n  });\r\n\r\n// Add a response interceptor\r\nsoxa.interceptors.response.use(function (response) {\r\n    // Any status code that lie within the range of 2xx cause this function to trigger\r\n    // Do something with response data\r\n    return response;\r\n  }, function (error) {\r\n    // Any status codes that falls outside the range of 2xx cause this function to trigger\r\n    // Do something with response error\r\n    return Promise.reject(error);\r\n  });\r\n```\r\n\r\nIf you need to remove an interceptor later you can.\r\n\r\n```ts\r\nconst myInterceptor = soxa.interceptors.request.use(function () {/*...*/});\r\nsoxa.interceptors.request.eject(myInterceptor);\r\n```\r\n\r\nYou can add interceptors to a custom instance of soxa.\r\n\r\n```ts\r\nconst instance = soxa.create();\r\ninstance.interceptors.request.use(function () {/*...*/});\r\n```\r\n\r\n## Handling Errors\r\n\r\n```ts\r\nsoxa.get('/user/12345')\r\n  .catch(function (error) {\r\n    if (error.response) {\r\n      // The request was made and the server responded with a status code\r\n      // that falls out of the range of 2xx\r\n      console.log(error.response.data);\r\n      console.log(error.response.status);\r\n      console.log(error.response.headers);\r\n    } else if (error.request) {\r\n      // The request was made but no response was received\r\n      // `error.request` is an instance of XMLHttpRequest in the browser and an instance of\r\n      // http.ClientRequest in node.js\r\n      console.log(error.request);\r\n    } else {\r\n      // Something happened in setting up the request that triggered an Error\r\n      console.log('Error', error.message);\r\n    }\r\n    console.log(error.config);\r\n  });\r\n```\r\n\r\nUsing the `validateStatus` config option, you can define HTTP code(s) that should throw an error.\r\n\r\n```ts\r\nsoxa.get('/user/12345', {\r\n  validateStatus: function (status) {\r\n    return status \u003c 500; // Reject only if the status code is greater than or equal to 500\r\n  }\r\n})\r\n```\r\n\r\nUsing `toJSON` you get an object with more information about the HTTP error.\r\n\r\n```ts\r\nsoxa.get('/user/12345')\r\n  .catch(function (error) {\r\n    console.log(error.toJSON());\r\n  });\r\n```\r\n\r\n## Cancellation\r\n\r\nYou can cancel a request using a *cancel token*.\r\n\r\n\u003e The soxa cancel token API is based on the withdrawn [cancelable promises proposal](https://github.com/tc39/proposal-cancelable-promises).\r\n\r\nYou can create a cancel token using the `CancelToken.source` factory as shown below:\r\n\r\n```ts\r\nconst CancelToken = soxa.CancelToken;\r\nconst source = CancelToken.source();\r\n\r\nsoxa.get('/user/12345', {\r\n  cancelToken: source.token\r\n}).catch(function (thrown) {\r\n  if (soxa.isCancel(thrown)) {\r\n    console.log('Request canceled', thrown.message);\r\n  } else {\r\n    // handle error\r\n  }\r\n});\r\n\r\nsoxa.post('/user/12345', {\r\n  name: 'new name'\r\n}, {\r\n  cancelToken: source.token\r\n})\r\n\r\n// cancel the request (the message parameter is optional)\r\nsource.cancel('Operation canceled by the user.');\r\n```\r\n\r\nYou can also create a cancel token by passing an executor function to the `CancelToken` constructor:\r\n\r\n```ts\r\nconst CancelToken = soxa.CancelToken;\r\nlet cancel;\r\n\r\nsoxa.get('/user/12345', {\r\n  cancelToken: new CancelToken(function executor(c) {\r\n    // An executor function receives a cancel function as a parameter\r\n    cancel = c;\r\n  })\r\n});\r\n\r\n// cancel the request\r\ncancel();\r\n```\r\n\r\n\u003e Note: you can cancel several requests with the same cancel token.\r\n\r\n## Using application/x-www-form-urlencoded format\r\n\r\nBy default, soxa serializes JavaScript objects to `JSON`. To send data in the `application/x-www-form-urlencoded` format instead, you can use one of the following options.\r\n\r\n```ts\r\nconst params = new URLSearchParams();\r\nparams.append('param1', 'value1');\r\nparams.append('param2', 'value2');\r\nsoxa.post('/foo', params);\r\n```\r\n\r\n## Credits\r\n\r\nsoxa is heavily inspired by the [axios](https://github.com/axios/axios) with new fetch adapter and support for typescript and deno.\r\n\r\n## License\r\n\r\n[MIT](LICENSE)\r\n\r\n\r\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ffakoua%2Fsoxa.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Ffakoua%2Fsoxa?ref=badge_large)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffakoua%2Fsoxa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffakoua%2Fsoxa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffakoua%2Fsoxa/lists"}