{"id":13449852,"url":"https://oakserver.github.io/oak/","last_synced_at":"2025-03-22T23:31:47.683Z","repository":{"id":39033869,"uuid":"161470791","full_name":"oakserver/oak","owner":"oakserver","description":"A middleware framework for handling HTTP with Deno, Node, Bun and Cloudflare Workers 🐿️ 🦕","archived":false,"fork":false,"pushed_at":"2025-01-06T09:44:10.000Z","size":53818,"stargazers_count":5238,"open_issues_count":54,"forks_count":235,"subscribers_count":40,"default_branch":"main","last_synced_at":"2025-01-14T11:10:52.318Z","etag":null,"topics":["deno","http-server","middleware-framework","middleware-frameworks","oak","router-middleware"],"latest_commit_sha":null,"homepage":"https://oakserver.org","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/oakserver.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"docs/CODE_OF_CONDUCT.md","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":"2018-12-12T10:20:46.000Z","updated_at":"2025-01-13T15:25:15.000Z","dependencies_parsed_at":"2024-02-10T00:26:57.272Z","dependency_job_id":"6bdfd45e-e6a1-4235-bd0e-2fea2e642e9e","html_url":"https://github.com/oakserver/oak","commit_stats":{"total_commits":654,"total_committers":77,"mean_commits":8.493506493506494,"dds":"0.14831804281345562","last_synced_commit":"26ae6bd80ea15efec3fb34452acba22b4473d150"},"previous_names":["kitsonk/oak"],"tags_count":101,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oakserver%2Foak","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oakserver%2Foak/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oakserver%2Foak/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oakserver%2Foak/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oakserver","download_url":"https://codeload.github.com/oakserver/oak/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244022636,"owners_count":20385134,"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","http-server","middleware-framework","middleware-frameworks","oak","router-middleware"],"created_at":"2024-07-31T06:00:58.756Z","updated_at":"2025-03-22T23:31:47.670Z","avatar_url":"https://github.com/oakserver.png","language":"TypeScript","readme":"# oak\n\n[![jsr.io/@oak/oak](https://jsr.io/badges/@oak/oak)](https://jsr.io/@oak/oak)\n[![jsr.io/@oak/oak score](https://jsr.io/badges/@oak/oak/score)](https://jsr.io/@oak/oak)\n[![deno.land/x/oak](https://deno.land/badge/oak/version)](https://deno.land/x/oak)\n[![npm Version](https://img.shields.io/npm/v/@oakserver/oak)](https://www.npmjs.com/package/@oakserver/oak)\n\n[![oak ci](https://github.com/oakserver/oak/workflows/ci/badge.svg)](https://github.com/oakserver/oak)\n[![codecov](https://codecov.io/gh/oakserver/oak/branch/main/graph/badge.svg?token=KEKZ52NXGP)](https://codecov.io/gh/oakserver/oak)\n\nA middleware framework for Deno's native HTTP server,\n[Deno Deploy](https://deno.com/deploy), Node.js 16.5 and later,\n[Cloudflare Workers](https://workers.cloudflare.com/) and\n[Bun](https://bun.sh/). It also includes a middleware router.\n\nThis middleware framework is inspired by [Koa](https://github.com/koajs/koa/)\nand middleware router inspired by\n[@koa/router](https://github.com/koajs/router/).\n\nThis README focuses on the mechanics of the oak APIs and is intended for those\nwho are familiar with JavaScript middleware frameworks like Express and Koa as\nwell as a decent understanding of Deno. If you aren't familiar with these,\nplease check out documentation on\n[oakserver.github.io/oak](https://oakserver.github.io/oak/).\n\nAlso, check out our [FAQs](https://oakserver.github.io/oak/FAQ) and the\n[awesome-oak](https://oakserver.github.io/awesome-oak/) site of community\nresources.\n\n\u003e [!NOTE]\n\u003e The examples in this README pull from `main` and are designed for Deno CLI or\n\u003e Deno Deploy, which may not make sense to do when you are looking to actually\n\u003e deploy a workload. You would want to \"pin\" to a particular version which is\n\u003e compatible with the version of Deno you are using and has a fixed set of APIs\n\u003e you would expect. `https://deno.land/x/` supports using git tags in the URL to\n\u003e direct you at a particular version. So to use version 13.0.0 of oak, you would\n\u003e want to import `https://deno.land/x/oak@v13.0.0/mod.ts`.\n\n## Usage\n\n### Deno CLI and Deno Deploy\n\noak is available on both [deno.land/x](https://deno.land/x/oak/) and\n[JSR](https://jsr.io/@oak/oak). To use from `deno.land/x`, import into a module:\n\n```ts\nimport { Application } from \"https://deno.land/x/oak/mod.ts\";\n```\n\nTo use from JSR, import into a module:\n\n```ts\nimport { Application } from \"jsr:@oak/oak\";\n```\n\nOr use the Deno CLI to add it to your project:\n\n```\ndeno add jsr:@oak/oak\n```\n\n### Node.js\n\noak is available for Node.js on both\n[npm](https://www.npmjs.com/package/@oakserver/oak) and\n[JSR](https://jsr.io/@oak/oak). To use from npm, install the package:\n\n```\nnpm i @oakserver/oak\n```\n\nAnd then import into a module:\n\n```js\nimport { Application } from \"@oakserver/oak\";\n```\n\nTo use from JSR, install the package:\n\n```\nnpx jsr i @oak/oak\n```\n\nAnd then import into a module:\n\n```js\nimport { Application } from \"@oak/oak/application\";\n```\n\n\u003e [!NOTE]\n\u003e Send, websocket upgrades and serving over TLS/HTTPS are not currently\n\u003e supported.\n\u003e\n\u003e In addition the Cloudflare Worker environment and execution context are not\n\u003e currently exposed to middleware.\n\n### Cloudflare Workers\n\noak is available for [Cloudflare Workers](https://workers.cloudflare.com/) on\n[JSR](https://jsr.io/@oak/oak). To use add the package to your Cloudflare Worker\nproject:\n\n```\nnpx jsr add @oak/oak\n```\n\nAnd then import into a module:\n\n```ts\nimport { Application } from \"@oak/oak/application\";\n```\n\nUnlike other runtimes, the oak application doesn't listen for incoming requests,\ninstead it handles worker fetch requests. A minimal example server would be:\n\n```ts\nimport { Application } from \"@oak/oak/application\";\n\nconst app = new Application();\n\napp.use((ctx) =\u003e {\n  ctx.response.body = \"Hello CFW!\";\n});\n\nexport default { fetch: app.fetch };\n```\n\n\u003e [!NOTE]\n\u003e Send and websocket upgrades are not currently supported.\n\n### Bun\n\noak is available for Bun on [JSR](https://jsr.io/@oak/oak). To use install the\npackage:\n\n```\nbunx jsr i @oak/oak\n```\n\nAnd then import into a module:\n\n```ts\nimport { Application } from \"@oak/oak/application\";\n```\n\n\u003e [!NOTE]\n\u003e Send and websocket upgrades are not currently supported.\n\n## Application, middleware, and context\n\nThe `Application` class coordinates managing the HTTP server, running\nmiddleware, and handling errors that occur when processing requests. Two of the\nmethods are generally used: `.use()` and `.listen()`. Middleware is added via\nthe `.use()` method and the `.listen()` method will start the server and start\nprocessing requests with the registered middleware.\n\nA basic usage, responding to every request with _Hello World!_:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\n\nconst app = new Application();\n\napp.use((ctx) =\u003e {\n  ctx.response.body = \"Hello World!\";\n});\n\nawait app.listen({ port: 8000 });\n```\n\nYou would then run this script in Deno like:\n\n```\n\u003e deno run --allow-net helloWorld.ts\n```\n\nFor more information on running code under Deno, or information on how to\ninstall the Deno CLI, check out the [Deno manual](https://deno.land/manual).\n\nThe middleware is processed as a stack, where each middleware function can\ncontrol the flow of the response. When the middleware is called, it is passed a\ncontext and reference to the \"next\" method in the stack.\n\nA more complex example:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\n\nconst app = new Application();\n\n// Logger\napp.use(async (ctx, next) =\u003e {\n  await next();\n  const rt = ctx.response.headers.get(\"X-Response-Time\");\n  console.log(`${ctx.request.method} ${ctx.request.url} - ${rt}`);\n});\n\n// Timing\napp.use(async (ctx, next) =\u003e {\n  const start = Date.now();\n  await next();\n  const ms = Date.now() - start;\n  ctx.response.headers.set(\"X-Response-Time\", `${ms}ms`);\n});\n\n// Hello World!\napp.use((ctx) =\u003e {\n  ctx.response.body = \"Hello World!\";\n});\n\nawait app.listen({ port: 8000 });\n```\n\nTo provide an HTTPS server, then the `app.listen()` options need to include the\noptions `.secure` option set to `true` and supply a `.certFile` and a `.keyFile`\noptions as well.\n\n### `.handle()` method\n\nThe `.handle()` method is used to process requests and receive responses without\nhaving the application manage the server aspect. This though is advanced usage\nand most users will want to use `.listen()`.\n\nThe `.handle()` method accepts up to three arguments. The first being a\n[`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) argument,\nand the second being a `Deno.Conn` argument. The third optional argument is a\nflag to indicate if the request was \"secure\" in the sense it originated from a\nTLS connection to the remote client. The method resolved with a\n[`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object\nor `undefined` if the `ctx.respond === true`.\n\nAn example:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\n\nconst app = new Application();\n\napp.use((ctx) =\u003e {\n  ctx.response.body = \"Hello World!\";\n});\n\nDeno.serve(async (request, info) =\u003e {\n  const res = await app.handle(request, info.remoteAddr);\n  return res ?? Response.error();\n});\n```\n\nAn instance of application has some properties as well:\n\n- `contextState` - Determines the method used to create state for a new context.\n  A value of `\"clone\"` will set the state as a clone of the app state. A value\n  of `\"prototype\"` means the app's state will be used as the prototype of the\n  context's state. A value of `\"alias\"` means that the application's state and\n  the context's state will be a reference to the same object. A value of\n  `\"empty\"` will initialize the context's state with an empty object.\n\n- `.jsonBodyReplacer` - An optional replacer function which will be applied to\n  JSON bodies when forming a response.\n\n- `.jsonBodyReviver` - An optional reviver function which will be applied when\n  reading JSON bodies in a request.\n\n- `.keys`\n\n  Keys to be used when signing and verifying cookies. The value can be set to an\n  array of keys, and instance of `KeyStack`, or an object which provides the\n  same interface as `KeyStack` (e.g. an instance of\n  [keygrip](https://github.com/crypto-utils/keygrip)). If just the keys are\n  passed, oak will manage the keys via `KeyStack` which allows easy key rotation\n  without requiring re-signing of data values.\n\n- `.proxy`\n\n  This defaults to `false`, but can be set via the `Application` constructor\n  options. This is intended to indicate the application is behind a proxy and\n  will use `X-Forwarded-Proto`, `X-Forwarded-Host`, and `X-Forwarded-For` when\n  processing the request, which should provide more accurate information about\n  the request.\n\n- `.state`\n\n  A record of application state, which can be strongly typed by specifying a\n  generic argument when constructing an `Application()`, or inferred by passing\n  a state object (e.g. `Application({ state })`).\n\n### Context\n\nThe context passed to middleware has several properties:\n\n- `.app`\n\n  A reference to the `Application` that is invoking this middleware.\n\n- `.cookies`\n\n  The `Cookies` instance for this context which allows you to read and set\n  cookies.\n\n- `.request`\n\n  The `Request` object which contains details about the request.\n\n- `.respond`\n\n  Determines if when middleware finishes processing, the application should send\n  the `.response` to the client. If `true` the response will be sent, and if\n  `false` the response will not be sent. The default is `true` but certain\n  methods, like `.upgrade()` and `.sendEvents()` will set this to `false`.\n\n- `.response`\n\n  The `Response` object which will be used to form the response sent back to the\n  requestor.\n\n- `.socket`\n\n  This will be `undefined` if the connection has not been upgraded to a web\n  socket. If the connection has been upgraded, the `.socket` interface will be\n  set.\n\n- `.state`\n\n  A record of application state, which can be strongly typed by specifying a\n  generic argument when constructing an `Application()`, or inferred by passing\n  a state object (e.g. `Application({ state })`).\n\nThe context passed to middleware has some methods:\n\n- `.assert()`\n\n  Makes an assertion, which if not true, throws an `HTTPError`, which subclass\n  is identified by the second argument, with the message being the third\n  argument.\n\n- `.send()`\n\n  Stream a file to the requesting client. See [Static content](#static-content)\n  below for more information.\n\n- `.sendEvents()`\n\n  Convert the current connection into a server-sent event response and return a\n  `ServerSentEventTarget` where messages and events can be streamed to the\n  client. This will set `.respond` to `false`.\n\n- `.throw()`\n\n  Throws an `HTTPError`, which subclass is identified by the first argument,\n  with the message being passed as the second.\n\n- `.upgrade()`\n\n  Attempt to upgrade the connection to a web socket connection, and return a\n  `WebSocket` interface. Previous version of oak, this would be a `Promise`\n  resolving with a `std/ws` web socket.\n\nUnlike other middleware frameworks, `context` does not have a significant amount\nof aliases. The information about the request is only located in `.request` and\nthe information about the response is only located in `.response`.\n\n#### Cookies\n\nThe `context.cookies` allows access to the values of cookies in the request, and\nallows cookies to be set in the response. It automatically secures cookies if\nthe `.keys` property is set on the application. Because `.cookies` uses the web\ncrypto APIs to sign and validate cookies, and those APIs work in an asynchronous\nway, the cookie APIs work in an asynchronous way. It has several methods:\n\n- `.get(key: string, options?: CookieGetOptions): Promise\u003cstring | undefined\u003e`\n\n  Attempts to retrieve the cookie out of the request and returns the value of\n  the cookie based on the key. If the applications `.keys` is set, then the\n  cookie will be verified against a signed version of the cookie. If the cookie\n  is valid, the promise will resolve with the value. If it is invalid, the\n  cookie signature will be set to deleted on the response. If the cookie was not\n  signed by the current key, it will be resigned and added to the response.\n\n- `.set(key: string, value: string, options?: CookieSetDeleteOptions): Promise\u003cvoid\u003e`\n\n  Will set a cookie in the response based on the provided key, value and any\n  options. If the applications `.keys` is set, then the cookie will be signed\n  and the signature added to the response. As the keys are signed\n  asynchronously, awaiting the `.set()` method is advised.\n\n#### Request\n\nThe `context.request` contains information about the request. It contains\nseveral properties:\n\n- `.body`\n\n  An object which provides access to the body of the request. See below for\n  details about the request body API.\n\n- `.hasBody`\n\n  Set to `true` if the request might have a body, or `false` if it does not. It\n  does not validate if the body is supported by the built in body parser though.\n\n  \u003e [!WARNING]\n  \u003e This is an unreliable API. In HTTP/2 in many situations you cannot determine\n  \u003e if a request has a body or not unless you attempt to read the body, due to\n  \u003e the streaming nature of HTTP/2. As of Deno 1.16.1, for HTTP/1.1, Deno\n  \u003e also reflects that behavior. The only reliable way to determine if a request\n  \u003e has a body or not is to attempt to read the body.\n\n  It is best to determine if a body might be meaningful to you with a given\n  method, and then attempt to read and process the body if it is meaningful in a\n  given context. For example `GET` and `HEAD` should never have a body, but\n  methods like `DELETE` and `OPTIONS` _might_ have a body and should be have\n  their body conditionally processed if it is meaningful to your application.\n\n- `.headers`\n\n  The headers for the request, an instance of `Headers`.\n\n- `.method`\n\n  A string that represents the HTTP method for the request.\n\n- `.originalRequest`\n\n  **DEPRECATED** this will be removed in a future release of oak.\n\n  The \"raw\" `NativeServer` request, which is an abstraction over the DOM\n  `Request` object. `.originalRequest.request` is the DOM `Request` instance\n  that is being processed. Users should generally avoid using these.\n\n- `.secure`\n\n  A shortcut for `.protocol`, returning `true` if HTTPS otherwise `false`.\n\n- `.source`\n\n  When running under Deno, `.source` will be set to the source web standard\n  `Request`. When running under NodeJS, this will be `undefined`.\n\n- `.url`\n\n  An instance of [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL)\n  which is based on the full URL for the request. This is in place of having\n  parts of the URL exposed on the rest of the request object.\n\nAnd several methods:\n\n- `.accepts(...types: string[])`\n\n  Negotiates the content type supported by the request for the response. If no\n  content types are passed, the method returns a prioritized array of accepted\n  content types. If content types are passed, the best negotiated content type\n  is returned. If no content type match `undefined` is returned.\n\n- `.acceptsEncodings(...encodings: string[])`\n\n  Negotiates the content encoding supported by the request for the response. If\n  no encodings are passed, the method returns a prioritized array of accepted\n  encodings. If encodings are passed, the best negotiated encoding is returned.\n  If no encodings match `undefined` is returned.\n\n- `.acceptsLanguages(...languages: string[])`\n\n  Negotiates the language the client is able to understand. Where a locale\n  variant takes preference. If no encodings are passed, the method returns a\n  prioritized array of understood languages. If languages are passed, the best\n  negotiated language is returned. If no languages match `undefined` is\n  returned.\n\n##### Request Body\n\n\u003e [!IMPORTANT]\n\u003e This API changed significantly in oak v13 and later. The previous API had\n\u003e grown organically since oak was created in 2018 and didn't represent any other\n\u003e common API. The API introduced in v13 aligns better to the Fetch API's\n\u003e `Request` way of dealing with the body, and should be more familiar to\n\u003e developers coming to oak for the first time.\n\nThe API for the oak request `.body` is inspired by the Fetch API's `Request` but\nwith some add functionality. The context's `request.body` is an instance of an\nobject which provides several properties:\n\n- `.has`\n\n  Set to `true` if the request might have a body, or `false` if it does not. It\n  does not validate if the body is supported by the built in body parser though.\n\n  \u003e [!IMPORTANT]\n  \u003e This is an unreliable API. In HTTP/2 in many situations you cannot determine\n  \u003e if a request has a body or not unless you attempt to read the body, due to\n  \u003e the streaming nature of HTTP/2. As of Deno 1.16.1, for HTTP/1.1, Deno\n  \u003e also reflects that behavior. The only reliable way to determine if a request\n  \u003e has a body or not is to attempt to read the body.\n\n  It is best to determine if a body might be meaningful to you with a given\n  method, and then attempt to read and process the body if it is meaningful in a\n  given context. For example `GET` and `HEAD` should never have a body, but\n  methods like `DELETE` and `OPTIONS` _might_ have a body and should be have\n  their body conditionally processed if it is meaningful to your application.\n\n- `.stream`\n\n  A `ReadableStream\u003cUint8Array\u003e` that will allow reading of the body in\n  `Uint8Array` chunks. This is akin the `.body` property in a Fetch API\n  `Request`.\n\n- `.used`\n\n  Set to `true` if the body has been used, otherwise set to `false`.\n\nIt also has several methods:\n\n- `arrayBuffer()`\n\n  Resolves with an `ArrayBuffer` that contains the contents of the body, if any.\n  Suitable for reading/handling binary data.\n\n- `blob()`\n\n  Resolves with a `Blob` that contains the contents of the body. Suitable for\n  reading/handling binary data.\n\n- `form()`\n\n  Resolves with a `URLSearchParams` which has been decoded from the contents of\n  a body. This is appropriate for a body with a content type of\n  `application/x-www-form-urlencoded`.\n\n- `formData()`\n\n  Resolves with a `FormData` instance which has been decoded from the contents\n  of a body. This is appropriate for a body with a content type of\n  `multipart/form-data`.\n\n- `json()`\n\n  Resolves with the data from the body parsed as JSON. If a `jsonBodyReviver`\n  has been specified in the application, it will be used when parsing the JSON.\n\n- `text()`\n\n  Resolves with a string that represents the contents of the body.\n\n- `type()`\n\n  Attempts to provide guidance of how the body is encoded which can be used to\n  determine what method to use to decode the body. The method returns a string\n  that represents the interpreted body type:\n\n  | Value         | Description                                                                                                                              |\n  | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |\n  | `\"binary\"`    | The body has a content type that indicates binary data and the `.arrayBuffer()`, `.blob()` or `.stream` should be used to read the body. |\n  | `\"form\"`      | The body is encoded as form data and `.form()` should be used to read the body.                                                          |\n  | `\"form-data\"` | The body is encoded as a multi-part form and `.formData()` should be used to read the body.                                              |\n  | `\"json\"`      | The body is encoded as JSON data and `.json()` should be used to read the body.                                                          |\n  | `\"text\"`      | The body is encoded as text and `.text()` should be used to read the body.                                                               |\n  | `\"unknown\"`   | Either there is no body or it was not possible to determine the body type based on the content type.                                     |\n\n  The `.type()` method also takes an optional argument of custom media types\n  that will be used when attempting to determine the type of the body. These are\n  then incorporated into the default media types. The value is an object where\n  the key is one of `binary`, `form`, `form-data`, `json`, or `text` and the\n  value is the appropriate media type in a format compatible with the\n  [type-is format](https://github.com/jshttp/type-is/?tab=readme-ov-file#typeisrequest-types).\n\n#### Response\n\nThe `context.response` contains information about the response which will be\nsent back to the requestor. It contains several properties:\n\n- `.body`\n\n  The body of the response, which can often be handled by the automatic response\n  body handling documented below.\n\n- `.headers`\n\n  A `Headers` instance which contains the headers for the response.\n\n- `.status`\n\n  An HTTP `Status` code that will be sent back with the response. If this is not\n  set before responding, oak will default to `200 OK` if there is a `.body`,\n  otherwise `404 Not Found`.\n\n- `.type`\n\n  A media type or extension to set the `Content-Type` header for the response.\n  For example, you can provide `txt` or `text/plain` to describe the body.\n\nAnd several methods:\n\n- `.redirect(url?: string | URL | REDIRECT_BACK, alt?: string | URL)`\n\n  A method to simplify redirecting the response to another URL. It will set the\n  `Location` header to the supplied `url` and the status to `302 Found` (unless\n  the status is already a `3XX` status). The use of symbol `REDIRECT_BACK` as\n  the `url` indicates that the `Referer` header in the request should be used as\n  the direction, with the `alt` being the alternative location if the `Referer`\n  is not set. If neither the `alt` nor the `Referer` are set, the redirect will\n  occur to `/`. A basic HTML (if the requestor supports it) or a text body will\n  be set explaining they are being redirected.\n\n- `.toDomResponse()`\n\n  This converts the information oak understands about the response to the Fetch\n  API `Response`. This will finalize the response, resulting in any further\n  attempt to modify the response to throw. This is intended to be used\n  internally within oak to be able to respond to requests.\n\n- `.with(response: Response)` and `.with(body?: BodyInit, init?: ResponseInit)`\n\n  This sets the response to a web standard `Response`. Note that this will\n  ignore/override any other information set on the response by other middleware\n  including things like headers or cookies to be set.\n\n### Automatic response body handling\n\nWhen the response `Content-Type` is not set in the headers of the `.response`,\noak will automatically try to determine the appropriate `Content-Type`. First it\nwill look at `.response.type`. If assigned, it will try to resolve the\nappropriate media type based on treating the value of `.type` as either the\nmedia type, or resolving the media type based on an extension. For example if\n`.type` was set to `\"html\"`, then the `Content-Type` will be set to\n`\"text/html\"`.\n\nIf `.type` is not set with a value, then oak will inspect the value of\n`.response.body`. If the value is a `string`, then oak will check to see if the\nstring looks like HTML, if so, `Content-Type` will be set to `text/html`\notherwise it will be set to `text/plain`. If the value is an object, other than\na `Uint8Array`, a `Deno.Reader`, or `null`, the object will be passed to\n`JSON.stringify()` and the `Content-Type` will be set to `application/json`.\n\nIf the type of body is a number, bigint or symbol, it will be coerced to a\nstring and treated as text.\n\nIf the value of body is a function, the function will be called with no\narguments. If the return value of the function is promise like, that will be\nawait, and the resolved value will be processed as above. If the value is not\npromise like, it will be processed as above.\n\n### Opening the server\n\nThe application method `.listen()` is used to open the server, start listening\nfor requests, and processing the registered middleware for each request. This\nmethod returns a promise when the server closes.\n\nOnce the server is open, before it starts processing requests, the application\nwill fire a `\"listen\"` event, which can be listened for via the\n`.addEventListener()` method. For example:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\n\nconst app = new Application();\n\napp.addEventListener(\"listen\", ({ hostname, port, secure }) =\u003e {\n  console.log(\n    `Listening on: ${secure ? \"https://\" : \"http://\"}${\n      hostname ?? \"localhost\"\n    }:${port}`,\n  );\n});\n\n// register some middleware\n\nawait app.listen({ port: 80 });\n```\n\n### Closing the server\n\nIf you want to close the application, the application supports the option of an\n[abort signal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal).\nHere is an example of using the signal:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\n\nconst app = new Application();\n\nconst controller = new AbortController();\nconst { signal } = controller;\n\n// Add some middleware using `app.use()`\n\nconst listenPromise = app.listen({ port: 8000, signal });\n\n// In order to close the server...\ncontroller.abort();\n\n// Listen will stop listening for requests and the promise will resolve...\nawait listenPromise;\n// and you can do something after the close to shutdown\n```\n\n### Error handling\n\nMiddleware can be used to handle other errors with middleware. Awaiting other\nmiddleware to execute while trapping errors works. So if you had an error\nhandling middleware that provides a well managed response to errors would work\nlike this:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\nimport { isHttpError } from \"jsr:@oak/commons/http_errors\";\nimport { Status } from \"jsr:@oak/commons/status\";\n\nconst app = new Application();\n\napp.use(async (ctx, next) =\u003e {\n  try {\n    await next();\n  } catch (err) {\n    if (isHttpError(err)) {\n      switch (err.status) {\n        case Status.NotFound:\n          // handle NotFound\n          break;\n        default:\n          // handle other statuses\n      }\n    } else {\n      // rethrow if you can't handle the error\n      throw err;\n    }\n  }\n});\n```\n\nUncaught middleware exceptions will be caught by the application. `Application`\nextends the global `EventTarget` in Deno, and when uncaught errors occur in the\nmiddleware or sending of responses, an `EventError` will be dispatched to the\napplication. To listen for these errors, you would add an event handler to the\napplication instance:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\n\nconst app = new Application();\n\napp.addEventListener(\"error\", (evt) =\u003e {\n  // Will log the thrown error to the console.\n  console.log(evt.error);\n});\n\napp.use((ctx) =\u003e {\n  // Will throw a 500 on every request.\n  ctx.throw(500);\n});\n\nawait app.listen({ port: 80 });\n```\n\n## Router\n\nThe `Router` class produces middleware which can be used with an `Application`\nto enable routing based on the pathname of the request.\n\n### Basic usage\n\nThe following example serves up a _RESTful_ service of a map of books, where\n`http://localhost:8000/book/` will return an array of books and\n`http://localhost:8000/book/1` would return the book with ID `\"1\"`:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\nimport { Router } from \"jsr:@oak/oak/router\";\n\nconst books = new Map\u003cstring, any\u003e();\nbooks.set(\"1\", {\n  id: \"1\",\n  title: \"The Hound of the Baskervilles\",\n  author: \"Conan Doyle, Arthur\",\n});\n\nconst router = new Router();\nrouter\n  .get(\"/\", (context) =\u003e {\n    context.response.body = \"Hello world!\";\n  })\n  .get(\"/book\", (context) =\u003e {\n    context.response.body = Array.from(books.values());\n  })\n  .get(\"/book/:id\", (context) =\u003e {\n    if (books.has(context?.params?.id)) {\n      context.response.body = books.get(context.params.id);\n    }\n  });\n\nconst app = new Application();\napp.use(router.routes());\napp.use(router.allowedMethods());\n\nawait app.listen({ port: 8000 });\n```\n\nA route passed is converted to a regular expression using\n[path-to-regexp](https://github.com/pillarjs/path-to-regexp), which means\nparameters expressed in the pattern will be converted. `path-to-regexp` has\nadvanced usage which can create complex patterns which can be used for matching.\nCheck out the\n[documentation for that library](https://github.com/pillarjs/path-to-regexp#parameters)\nif you have advanced use cases.\n\nIn most cases, the type of `context.params` is automatically inferred from the\npath template string through typescript magic. In more complex scenarios this\nmight not yield the correct result however. In that case you can override the\ntype with `router.get\u003cRouteParams\u003e`, where `RouteParams` is the explicit type\nfor `context.params`.\n\n### Nested routers\n\nNesting routers is supported. The following example responds to\n`http://localhost:8000/forums/oak/posts` and\n`http://localhost:8000/forums/oak/posts/nested-routers`.\n\n```typescript\nimport { Application } from \"jsr:@oak/oak/application\";\nimport { Router } from \"jsr:@oak/oak/router\";\n\nconst posts = new Router()\n  .get(\"/\", (ctx) =\u003e {\n    ctx.response.body = `Forum: ${ctx.params.forumId}`;\n  })\n  .get(\"/:postId\", (ctx) =\u003e {\n    ctx.response.body =\n      `Forum: ${ctx.params.forumId}, Post: ${ctx.params.postId}`;\n  });\n\nconst forums = new Router().use(\n  \"/forums/:forumId/posts\",\n  posts.routes(),\n  posts.allowedMethods(),\n);\n\nawait new Application().use(forums.routes()).listen({ port: 8000 });\n```\n\n## Static content\n\nThe function `send()` is designed to serve static content as part of a\nmiddleware function. In the most straight forward usage, a root is provided and\nrequests provided to the function are fulfilled with files from the local file\nsystem relative to the root from the requested path.\n\nA basic usage would look something like this:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\n\nconst app = new Application();\n\napp.use(async (context, next) =\u003e {\n  try {\n    await context.send({\n      root: `${Deno.cwd()}/examples/static`,\n      index: \"index.html\",\n    });\n  } catch {\n    await next();\n  }\n});\n\nawait app.listen({ port: 8000 });\n```\n\n`send()` automatically supports features like providing `ETag` and\n`Last-Modified` headers in the response as well as processing `If-None-Match`\nand `If-Modified-Since` headers in the request. This means when serving up\nstatic content, clients will be able to rely upon their cached versions of\nassets instead of re-downloading them.\n\n### ETag support\n\nThe `send()` method automatically supports generating an `ETag` header for\nstatic assets. The header allows the client to determine if it needs to\nre-download an asset or not, but it can be useful to calculate `ETag`s for other\nscenarios.\n\nThere is a middleware function that assesses the `context.reponse.body` and\ndetermines if it can create an `ETag` header for that body type, and if so sets\nthe `ETag` header on the response. Basic usage would look something like this:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\nimport { factory } from \"jsr:@oak/oak/etag\";\n\nconst app = new Application();\n\napp.use(factory());\n\n// ... other middleware for the application\n```\n\nThere is also a function which retrieves an entity for a given context based on\nwhat it logical to read into memory which can be passed to the etag calculate\nthat is part of the Deno std library:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\nimport { getEntity } from \"jsr:@oak/oak/etag\";\nimport { calculate } from \"jsr:@std/http/etag\";\n\nconst app = new Application();\n\n// The context.response.body has already been set...\n\napp.use(async (ctx) =\u003e {\n  const entity = await getEntity(ctx);\n  if (entity) {\n    const etag = await calculate(entity);\n  }\n});\n```\n\n## Fetch API and `Deno.serve()` migration\n\nIf you are migrating from `Deno.serve()` or adapting code that is designed for\nthe web standard Fetch API `Request` and `Response`, there are a couple features\nof oak to assist.\n\n### `ctx.request.source`\n\nWhen running under Deno, this will be set to a Fetch API `Request`, giving\ndirect access to the original request.\n\n### `ctx.response.with()`\n\nThis method will accept a Fetch API `Response` or create a new response based\non the provided `BodyInit` and `ResponseInit`. This will also finalize the\nresponse and ignores anything that may have been set on the oak `.response`.\n\n### `middleware/serve#serve()` and `middelware/serve#route()`\n\nThese two middleware generators can be used to adapt code that operates more\nlike the `Deno.serve()` in that it provides a Fetch API `Request` and expects\nthe handler to resolve with a Fetch API `Response`.\n\nAn example of using `serve()` with `Application.prototype.use()`:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\nimport { serve } from \"jsr:@oak/oak/serve\";\n\nconst app = new Application();\n\napp.use(serve((req, ctx) =\u003e {\n  console.log(req.url);\n  return new Response(\"Hello world!\");\n}));\n\napp.listen();\n```\n\nAnd a similar solution works with `route()` where the context contains the\ninformation about the router, like the params:\n\n```ts\nimport { Application } from \"jsr:@oak/oak/application\";\nimport { Router } from \"jsr:@oak/oak/router\";\nimport { route } from \"jsr:@oak/oak/serve\";\n\nconst app = new Application;\n\nconst router = new Router();\n\nrouter.get(\"/books/:id\", route((req, ctx) =\u003e {\n  console.log(ctx.params.id);\n  return Response.json({ title: \"hello world\", id: ctx.params.id });\n}));\n\napp.use(router.routes());\n\napp.listen();\n```\n\n## Testing\n\nThe `mod.ts` exports an object named `testing` which contains some utilities for\ntesting oak middleware you might create. See the\n[Testing with oak](https://oakserver.github.io/oak/testing) for more\ninformation.\n\n---\n\nThere are several modules that are directly adapted from other modules. They\nhave preserved their individual licenses and copyrights. All of the modules,\nincluding those directly adapted are licensed under the MIT License.\n\nAll additional work is copyright 2018 - 2025 the oak authors. All rights\nreserved.\n","funding_links":[],"categories":["General"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/oakserver.github.io%2Foak%2F","html_url":"https://awesome.ecosyste.ms/projects/oakserver.github.io%2Foak%2F","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/oakserver.github.io%2Foak%2F/lists"}