
# Fetch Handler

> Get familiar with srvx fetch server handler and `ServerRequest`.

Request handler is defined via `fetch` key since it is similar to [fetch][fetch] API. The input is a [Request][Request] object and handler should return a [Response][Response] or a promise if the server handler is async.

**Example:**

```js
import { serve } from "srvx";

serve({
  async fetch(request) {
    return new Response(
      `
        <h1>👋 Hello there</h1>
        <p>You are visiting ${request.url} from ${request.ip}</p>
      `,
      { headers: { "Content-Type": "text/html" } },
    );
  },
});
```

## Extended Request (`ServerRequest`)

> [!TIP]
> You can use `ServerRequest` type export from `srvx` as type of `request`.

### `request.ip?`

Using `request.ip` allows to access connected client's IP address.

```js
import { serve } from "srvx";

serve({
  fetch: (request) => new Response(`Your ip address is "${request.ip}"`),
});
```

### `request.tls?`

TLS connection state, including the client (peer) certificate, negotiated protocol and cipher. Added by the opt-in [`mtlsPlugin()`](/guide/tls#mutual-tls-mtls) (`srvx/mtls`); `undefined` for plain HTTP requests or when the plugin is not enabled.

:read-more{to="/guide/tls" title="TLS & mutual TLS"}

### `request.waitUntil?`

Tell the runtime about an ongoing operation that shouldn't close until the promise resolves.

```js
import { serve } from "srvx";

async function logRequest(request) {
  await fetch("https://telemetry.example.com", {
    method: "POST",
    body: JSON.stringify({
      method: request.method,
      url: request.url,
      ip: request.ip,
    }),
  });
}

serve({
  fetch: (request) => {
    request.waitUntil(logRequest(request));
    return new Response("OK");
  },
});
```

### `request.runtime?.name?`

Runtime name. Can be `"bun"`, `"deno"`, `"node"`, `"cloudflare"` or any other string.

### `request.runtime?.bun?`

Using `request.runtime.bun?.server` you can access to the underlying Bun server.

### `request.runtime?.deno?`

Using `request.runtime.deno?.server` you can access to the underlying Deno server.

Using `request.deno?.info` you can access to the extra request information provided by Deno.

### `request.runtime?.node?`

[Node.js][Node.js] is supported through a proxy that wraps [node:IncomingMessage][IncomingMessage] as [Request][Request] and converting final state of [node:ServerResponse][ServerResponse] to [Response][Response].

If access to the underlying [Node.js][Node.js] request and response objects is required (only in Node.js runtime), you can access them via `request.runtime?.node?.req` ([node:IncomingMessage][IncomingMessage]) and `request.runtime?.node?.res` ([node:ServerResponse][ServerResponse]).

```js
import { serve } from "srvx";

serve({
  fetch: (request) => {
    if (request.runtime.node) {
      console.log("Node.js req url:", request.runtime.node?.req.url);
      request.runtime.node.res.statusCode = 418; // I'm a teapot!
    }
    return new Response("ok");
  },
});
```

> [!TIP]
> srvx implementation of [Request][Request] proxy directly uses the underlying [node:IncomingMessage][IncomingMessage] as source of truth. Any changes to [Request][Request] will be reflected to the underlying [node:IncomingMessage][IncomingMessage] and vice versa.

:read-more{to="/guide/node" title="Node.js support"}

[Deno]: https://deno.com/
[Bun]: https://bun.sh/
[Node.js]: https://nodejs.org/
[fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
[Request]: https://developer.mozilla.org/en-US/docs/Web/API/Request
[Response]: https://developer.mozilla.org/en-US/docs/Web/API/Response
[IncomingMessage]: https://nodejs.org/api/http.html#http_class_http_incomingmessage
[ServerResponse]: https://nodejs.org/api/http.html#http_class_http_serverresponse
