denooak

Can oak server hook into deno's std serve server?


Given an existing native deno http server like this:

import {serve} from "https://deno.land/std@0.153.0/http/server.ts";
import { handle } from './astro/dist/server/entry.mjs';

serve((req: Request) => {
  console.log(req)
  return handle(req);
});

Is it possible to hook in an oak app where the console.log is?


Solution

  • An instance of Oak's Application class has a handle method for this purpose. From the readme:

    .handle() method

    The .handle() method is used to process requests and receive responses without having the application manage the server aspect. This though is advanced usage and most users will want to use .listen().

    The .handle() method accepts up to three arguments. The first being a Request argument, and the second being a Deno.Conn argument. The third optional argument is a flag to indicate if the request was "secure" in the sense it originated from a TLS connection to the remote client. The method resolved with a Response object or undefined if the ctx.respond === true.

    An example:

    import { Application } from "https://deno.land/x/oak/mod.ts";
    
    const app = new Application();
    
    app.use((ctx) => {
      ctx.response.body = "Hello World!";
    });
    
    const listener = Deno.listen({ hostname: "localhost", port: 8000 });
    
    for await (const conn of listener) {
      (async () => {
        const requests = Deno.serveHttp(conn);
        for await (const { request, respondWith } of requests) {
          const response = await app.handle(request, conn);
          if (response) {
            respondWith(response);
          }
        }
      });
    }
    

    The example above uses Deno's low-level http API, so here's a contrived example to illustrate using it with the serve function from your question:

    ./server.ts:

    import { serve } from "https://deno.land/std@0.153.0/http/server.ts";
    import { Application } from "https://deno.land/x/oak@v11.1.0/mod.ts";
    
    const app = new Application();
    
    app.use((ctx) => {
      if (ctx.request.url.pathname === "/") {
        ctx.response.body = "You're at the root and this response came from Oak";
      } else ctx.respond = false;
    });
    
    await serve(async (request) => {
      const response = await app.handle(request);
      return response ??
        new Response("You're not at the root and Oak didn't return a response");
    }, { hostname: "localhost", port: 8000 });