{"id":13718746,"url":"https://github.com/cmorten/oak-http-proxy","last_synced_at":"2025-04-30T13:50:15.736Z","repository":{"id":48703728,"uuid":"290468584","full_name":"cmorten/oak-http-proxy","owner":"cmorten","description":"Proxy middleware for Deno Oak HTTP servers. 🐿 🦕","archived":false,"fork":false,"pushed_at":"2024-01-28T22:05:27.000Z","size":246,"stargazers_count":43,"open_issues_count":1,"forks_count":5,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-21T01:19:49.212Z","etag":null,"topics":["deno","deno-doc","deno-module","denojs","denoland","http-proxy","oak","oak-http-proxy","proxy-middleware"],"latest_commit_sha":null,"homepage":"https://cmorten.github.io/oak-http-proxy/","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/cmorten.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS.md","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["cmorten"]}},"created_at":"2020-08-26T10:40:03.000Z","updated_at":"2024-10-10T19:10:53.000Z","dependencies_parsed_at":"2024-08-03T01:37:36.693Z","dependency_job_id":null,"html_url":"https://github.com/cmorten/oak-http-proxy","commit_stats":null,"previous_names":["asos-craigmorten/oak-http-proxy"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmorten%2Foak-http-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmorten%2Foak-http-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmorten%2Foak-http-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmorten%2Foak-http-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cmorten","download_url":"https://codeload.github.com/cmorten/oak-http-proxy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251714745,"owners_count":21631779,"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":["deno","deno-doc","deno-module","denojs","denoland","http-proxy","oak","oak-http-proxy","proxy-middleware"],"created_at":"2024-08-03T01:00:36.948Z","updated_at":"2025-04-30T13:50:15.643Z","avatar_url":"https://github.com/cmorten.png","language":"TypeScript","funding_links":["https://github.com/sponsors/cmorten"],"categories":["Modules"],"sub_categories":["Web framework"],"readme":"# oak-http-proxy\n\nProxy middleware for Deno Oak HTTP servers.\n\n[![GitHub tag](https://img.shields.io/github/tag/cmorten/oak-http-proxy)](https://github.com/cmorten/oak-http-proxy/tags/) ![Test](https://github.com/cmorten/oak-http-proxy/workflows/Test/badge.svg) [![deno doc](https://doc.deno.land/badge.svg)](https://doc.deno.land/https/deno.land/x/oak_http_proxy/mod.ts) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com) [![GitHub issues](https://img.shields.io/github/issues/cmorten/oak-http-proxy)](https://img.shields.io/github/issues/cmorten/oak-http-proxy)\n![GitHub stars](https://img.shields.io/github/stars/cmorten/oak-http-proxy) ![GitHub forks](https://img.shields.io/github/forks/cmorten/oak-http-proxy) ![oak-http-proxy License](https://img.shields.io/github/license/cmorten/oak-http-proxy) [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://GitHub.com/cmorten/oak-http-proxy/graphs/commit-activity)\n\n\u003cp align=\"left\"\u003e\n   \u003ca href=\"https://deno.land/x/oak_http_proxy\"\u003e\u003cimg src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fdeno-visualizer.danopia.net%2Fshields%2Flatest-version%2Fx%2Foak_http_proxy%2Fmod.ts\" alt=\"oak-http-proxy latest /x/ version\" /\u003e\u003c/a\u003e\n   \u003ca href=\"https://deno-visualizer.danopia.net/dependencies-of/https/deno.land/x/oak_http_proxy/mod.ts\"\u003e\u003cimg src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fdeno-visualizer.danopia.net%2Fshields%2Fdep-count%2Fx%2Foak_http_proxy%2Fmod.ts\" alt=\"oak-http-proxy dependency count\" /\u003e\u003c/a\u003e\n   \u003ca href=\"https://deno-visualizer.danopia.net/dependencies-of/https/deno.land/x/oak_http_proxy/mod.ts\"\u003e\u003cimg src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fdeno-visualizer.danopia.net%2Fshields%2Fupdates%2Fx%2Foak_http_proxy%2Fmod.ts\" alt=\"oak-http-proxy dependency outdatedness\" /\u003e\u003c/a\u003e\n   \u003ca href=\"https://deno-visualizer.danopia.net/dependencies-of/https/deno.land/x/oak_http_proxy/mod.ts\"\u003e\u003cimg src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fdeno-visualizer.danopia.net%2Fshields%2Fcache-size%2Fx%2Foak_http_proxy%2Fmod.ts\" alt=\"oak-http-proxy cached size\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n```ts\nimport { proxy } from \"https://deno.land/x/oak_http_proxy@2.3.0/mod.ts\";\nimport { Application } from \"https://deno.land/x/oak@v12.6.2/mod.ts\";\n\nconst app = new Application();\n\napp.use(proxy(\"https://github.com/oakserver/oak\"));\n\nawait app.listen({ port: 3000 });\n```\n\n## Installation\n\nThis is a [Deno](https://deno.land/) module available to import direct from this repo and via the [Deno Registry](https://deno.land/x).\n\nBefore importing, [download and install Deno](https://deno.land/#installation).\n\nYou can then import oak-http-proxy straight into your project:\n\n```ts\nimport { proxy } from \"https://deno.land/x/oak_http_proxy@2.3.0/mod.ts\";\n```\n\noak-http-proxy is also available on [nest.land](https://nest.land/package/oak-http-proxy), a package registry for Deno on the Blockchain.\n\n```ts\nimport { proxy } from \"https://x.nest.land/oak-http-proxy@2.3.0/mod.ts\";\n```\n\n## Docs\n\n- [oak-http-proxy Type Docs](https://cmorten.github.io/oak-http-proxy/)\n- [oak-http-proxy Deno Docs](https://doc.deno.land/https/deno.land/x/oak_http_proxy/mod.ts)\n- [License](https://github.com/cmorten/oak-http-proxy/blob/main/LICENSE.md)\n- [Changelog](https://github.com/cmorten/oak-http-proxy/blob/main/.github/CHANGELOG.md)\n\n## Usage\n\n### URL\n\nThe url argument that can be a string, URL or a function that returns a string or URL. This is used as the url to proxy requests to. Query string parameters and hashes are transferred from incoming request urls onto the proxy url.\n\n```ts\nrouter.get(\"/string\", proxy(\"http://google.com\"));\n\nrouter.get(\"/url\", proxy(new URL(\"http://google.com\")));\n\nrouter.get(\n  \"/function\",\n  proxy((ctx) =\u003e new URL(\"http://google.com\"))\n);\n```\n\nNote: Unmatched path segments of the incoming request url _are not_ transferred to the outbound proxy URL. For dynamic proxy urls use the function form.\n\n### Streaming\n\nProxy requests and user responses are piped/streamed/chunked by default.\n\nIf you define a response modifier (`srcResDecorator`, `srcResHeaderDecorator`),\nor need to inspect the response before continuing (`filterRes`), streaming is\ndisabled, and the request and response are buffered. This can cause performance\nissues with large payloads.\n\n### Proxy Options\n\nYou can also provide several options which allow you to filter, customize and decorate proxied requests and responses.\n\n```ts\napp.use(proxy(\"http://google.com\", proxyOptions));\n```\n\n#### filterReq(req, res) (supports Promises)\n\nThe `filterReq` option can be used to limit what requests are proxied.\n\nReturn false to continue to execute the proxy; return true to skip the proxy for this request.\n\n```ts\napp.use(\n  \"/proxy\",\n  proxy(\"www.google.com\", {\n    filterReq: (req, res) =\u003e {\n      return req.method === \"GET\";\n    },\n  })\n);\n```\n\nPromise form:\n\n```ts\napp.use(\n  proxy(\"localhost:12346\", {\n    filterReq: (req, res) =\u003e {\n      return new Promise((resolve) =\u003e {\n        resolve(req.method === \"GET\");\n      });\n    },\n  })\n);\n```\n\n#### srcResDecorator(req, res, proxyRes, proxyResData) (supports Promise)\n\nDecorate the inbound response object from the proxied request.\n\n```ts\nrouter.get(\n  \"/proxy\",\n  proxy(\"www.example.com\", {\n    srcResDecorator: (req, res, proxyRes, proxyResData) =\u003e {\n      data = JSON.parse(new TextDecoder().decode(proxyResData));\n      data.newProperty = \"exciting data\";\n\n      return JSON.stringify(data);\n    },\n  })\n);\n```\n\n```ts\napp.use(\n  proxy(\"httpbin.org\", {\n    srcResDecorator: (req, res, proxyRes, proxyResData) =\u003e {\n      return new Promise((resolve) =\u003e {\n        proxyResData.message = \"Hello Deno!\";\n\n        setTimeout(() =\u003e {\n          resolve(proxyResData);\n        }, 200);\n      });\n    },\n  })\n);\n```\n\n##### 304 - Not Modified\n\nWhen your proxied service returns 304 Not Modified this step will be skipped, since there should be no body to decorate.\n\n##### Exploiting references\n\nThe intent is that this be used to modify the proxy response data only.\n\nNote: The other arguments are passed by reference, so you _can_ currently exploit this to modify either response's headers, for instance, but this is not a reliable interface.\n\n#### memoizeUrl\n\nDefaults to `true`.\n\nWhen true, the `url` argument will be parsed on first request, and memoized for subsequent requests.\n\nWhen `false`, `url` argument will be parsed on each request.\n\nFor example:\n\n```ts\nfunction coinToss() {\n  return Math.random() \u003e 0.5;\n}\n\nfunction getUrl() {\n  return coinToss() ? \"http://yahoo.com\" : \"http://google.com\";\n}\n\napp.use(\n  proxy(getUrl, {\n    memoizeUrl: false,\n  })\n);\n```\n\nIn this example, when `memoizeUrl: false`, the coinToss occurs on each request, and each request could get either value.\n\nConversely, When `memoizeUrl: true`, the coinToss would occur on the first request, and all additional requests would return the value resolved on the first request.\n\n### srcResHeaderDecorator\n\nDecorate the inbound response headers from the proxied request.\n\n```ts\nrouter.get(\n  \"/proxy\",\n  proxy(\"www.google.com\", {\n    srcResHeaderDecorator(headers, req, res, proxyReq, proxyRes) {\n      return headers;\n    },\n  })\n);\n```\n\n#### filterRes(proxyRes, proxyResData) (supports Promise form)\n\nAllows you to inspect the proxy response, and decide if you want to continue processing (via oak-http-proxy) or continue onto the next middleware.\n\n```ts\nrouter.get(\n  \"/proxy\",\n  proxy(\"www.google.com\", {\n    filterRes(proxyRes) {\n      return proxyRes.status === 404;\n    },\n  })\n);\n```\n\n### proxyErrorHandler\n\nBy default, `oak-http-proxy` will throw any errors except `ECONNRESET` and `ECONTIMEDOUT` via `ctx.throw(err)`, so that your application can handle or react to them, or just drop through to your default error handling.\n\nIf you would like to modify this behavior, you can provide your own `proxyErrorHandler`.\n\n```ts\n// Example of skipping all error handling.\n\napp.use(\n  proxy(\"localhost:12346\", {\n    proxyErrorHandler(err, ctx, next) {\n      ctx.throw(err);\n    },\n  })\n);\n\n// Example of rolling your own error handler\n\napp.use(\n  proxy(\"localhost:12346\", {\n    proxyErrorHandler(err, ctx, next) {\n      switch (err \u0026\u0026 err.code) {\n        case \"ECONNRESET\": {\n          ctx.response.status = 405;\n\n          return;\n        }\n        case \"ECONNREFUSED\": {\n          ctx.response.status = 200;\n\n          return;\n        }\n        default: {\n          ctx.throw(err);\n        }\n      }\n    },\n  })\n);\n```\n\n#### proxyReqUrlDecorator(url, req) (supports Promise form)\n\nDecorate the outbound proxied request url.\n\nThe returned url is used for the `fetch` method internally.\n\n```ts\nrouter.get(\n  \"/proxy\",\n  proxy(\"www.google.com\", {\n    proxyReqUrlDecorator(url, req) {\n      url.pathname = \"/\";\n\n      return url;\n    },\n  })\n);\n```\n\nYou can also use Promises:\n\n```ts\nrouter.get(\n  \"/proxy\",\n  proxy(\"localhost:3000\", {\n    proxyReqOptDecorator(url, req) {\n      return new Promise((resolve, reject) =\u003e {\n        if (url.pathname === \"/login\") {\n          url.port = 8080;\n        }\n\n        resolve(url);\n      });\n    },\n  })\n);\n```\n\nGenerally it is advised to use the function form for the passed URL argument as this provides the full context object whereas the `proxyReqOptDecorator` passes only the `context.request` object.\n\nPotential use cases for `proxyReqOptDecorator` include:\n\n- Overriding default protocol behaviour.\n- Overriding default query-string and hash transfer behaviour.\n\n#### proxyReqInitDecorator(proxyReqOpts, req) (supports Promise form)\n\nDecorate the outbound proxied request initialization options.\n\nThis configuration will be used within the `fetch` method internally to make the request to the provided url.\n\n```ts\nrouter.get(\n  \"/proxy\",\n  proxy(\"www.google.com\", {\n    proxyReqInitDecorator(proxyReqOpts, srcReq) {\n      // you can update headers\n      proxyReqOpts.headers.set(\"Content-Type\", \"text/html\");\n      // you can change the method\n      proxyReqOpts.method = \"GET\";\n\n      return proxyReqOpts;\n    },\n  })\n);\n```\n\nYou can also use Promises:\n\n```ts\nrouter.get(\n  \"/proxy\",\n  proxy(\"www.google.com\", {\n    proxyReqOptDecorator(proxyReqOpts, srcReq) {\n      return new Promise((resolve, reject) =\u003e {\n        proxyReqOpts.headers.set(\"Content-Type\", \"text/html\");\n\n        resolve(proxyReqOpts);\n      });\n    },\n  })\n);\n```\n\n#### secure\n\nNormally, your proxy request will be made on the same protocol as the `url` parameter. If you'd like to force the proxy request to be https, use this option.\n\n```ts\napp.use(\n  \"/proxy\",\n  proxy(\"http://www.google.com\", {\n    secure: true,\n  })\n);\n```\n\nNote: if the proxy is passed a url without a protocol then HTTP will be used by default unless overridden by this option.\n\n#### preserveHostHeader\n\nYou can copy the host HTTP header to the proxied Oak server using the `preserveHostHeader` option.\n\n```ts\nrouter.get(\n  \"/proxy\",\n  proxy(\"www.google.com\", {\n    preserveHostHeader: true,\n  })\n);\n```\n\n#### parseReqBody\n\nThe `parseReqBody` option allows you to control whether the request body should be parsed and sent with the proxied request. If set to `false` then an incoming request body will not be sent with the proxied request.\n\n#### reqAsBuffer\n\nConfigure whether the proxied request body should be sent as a UInt8Array buffer.\n\nIgnored if `parseReqBody` is set to `false`.\n\n```ts\nrouter.get(\n  \"/proxy\",\n  proxy(\"www.google.com\", {\n    reqAsBuffer: true,\n  })\n);\n```\n\n#### reqBodyEncoding\n\nThe request body encoding to use. Currently only \"utf-8\" is supported.\n\nIgnored if `parseReqBody` is set to `false`.\n\n```ts\nrouter.get(\n  \"/post\",\n  proxy(\"httpbin.org\", {\n    reqBodyEncoding: \"utf-8\",\n  })\n);\n```\n\n#### reqBodyLimit\n\nThe request body size limit to use.\n\nIgnored if `reqBodyLimit` is set to `Infinity`.\n\n```ts\nrouter.get(\n  \"/post\",\n  proxy(\"httpbin.org\", {\n    reqBodyLimit: 10_485_760, // 10MB\n  })\n);\n```\n\n#### timeout\n\nConfigure a timeout in ms for the outbound proxied request.\n\nIf not provided the request will never time out.\n\nTimed-out requests will respond with 504 status code and a X-Timeout-Reason header.\n\n```ts\nrouter.get(\n  \"/\",\n  proxy(\"httpbin.org\", {\n    timeout: 2000, // in milliseconds, two seconds\n  })\n);\n```\n\n## Contributing\n\n[Contributing guide](https://github.com/cmorten/oak-http-proxy/blob/main/.github/CONTRIBUTING.md)\n\n---\n\n## License\n\noak-http-proxy is licensed under the [MIT License](./LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmorten%2Foak-http-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcmorten%2Foak-http-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmorten%2Foak-http-proxy/lists"}