oak icon indicating copy to clipboard operation
oak copied to clipboard

Access the original request (it's not `originalRequest`..)

Open Industrial opened this issue 2 years ago • 2 comments

Hi!

I want to serve an API with Oak that requires a Request and returns a Response. I need to wrap this in an Oak request.

I found that the types for Oak request/response's are also called Request and Response. This is confusing and might better be named OakRequest and OakResponse, but this is sematics.

I found the originalRequest field on the Request class of oak but this request is still not the basic Request passed by the Deno HTTP server. How do I access that request?

gr,

Tom

Industrial avatar Jun 04 '22 09:06 Industrial

I solved it with this:

import { Context as OakContext } from 'https://deno.land/x/[email protected]/mod.ts';

export async function wrapOakRequest(
  ctx: OakContext,
  fn: (request: Request) => Promise<Response>,
) {
  const req = new Request(ctx.request.url.toString(), {
    body: ctx.request.originalRequest.getBody().body,
    headers: ctx.request.headers,
    method: ctx.request.method,
  });

  const response = await fn(req);

  ctx.response.status = response.status;
  ctx.response.headers = response.headers;
  ctx.response.body = response.body;
}

Industrial avatar Jun 04 '22 19:06 Industrial

Hey thanks a lot @industrial 🙏 Can use oak now to serve Remix

Just modified it slightly so I can just

app.use(wrapOakRequest(remixHandler));
export function wrapOakRequest(
  fn: (request: Request) => Promise<Response>,
) {
  return async (ctx: OakContext) => {
    const req = new Request(ctx.request.url.toString(), {
      body: ctx.request.originalRequest.getBody().body,
      headers: ctx.request.headers,
      method: ctx.request.method,
    });

    const response = await fn(req);

    ctx.response.status = response.status;
    ctx.response.headers = response.headers;
    ctx.response.body = response.body;
  };
}

CanRau avatar Jun 21 '22 21:06 CanRau

This essentially sounds like the inverse of Application.prototype.handle() where you have some sort of function that you want to use as middleware, but is expecting a fetch standard Request and returns a fetch standard Response.

kitsonk avatar Apr 25 '23 06:04 kitsonk

I want to do the same, but using two simple functions. I have the following to convert an Oak Request to a web-standard Request:

function toWebRequest(oakRequest: OakRequest): Request {
  return new Request(oakRequest.url, {
    ...oakRequest,
    body: oakRequest.originalRequest.getBody().body,
  });
}

How would I do toOakResponse(response: Response): OakResponse?

iuioiua avatar Jun 20 '23 23:06 iuioiua

This essentially sounds like the inverse of Application.prototype.handle() where you have some sort of function that you want to use as middleware, but is expecting a fetch standard Request and returns a fetch standard Response.

Another example use case would be migrating from an application that was using "Serve" (supabase functions in my case).

I have a bunch of functions that accept/return stdlib Request/Response. I now want to introduce Oak for routing & middleware, but have to refactor a bunch of types needlessly

ChuckJonas avatar Sep 23 '23 03:09 ChuckJonas

Ok, I have added a few features. There is new middleware called serve() and route() which make it easier to deal with using Fetch API "handlers" as middleware.

An example of using serve() with Application.prototype.use():

import { Application, serve } from "https://deno.land/x/oak/mod.ts";

const app = new Application();

app.use(serve((req, ctx) => {
  console.log(req.url);
  return new Response("Hello world!");
}));

app.listen();

And a similar solution works with route() where the context contains the information about the router, like the params:

import { Application, route, Router } from "https://deno.land/x/oak/mod.ts";

const app = new Application;

const router = new Router();

router.get("/books/:id", route((req, ctx)) => {
  console.log(ctx.params.id);
  return Response.json({ title: "hello world", id: ctx.params.id });
});

app.use(router.routes());

app.listen();

In addition I added ctx.request.source which will be set to the original Request and people can use ctx.response.with() to supply a web standard Response instead of having to do other things. This should give a lot of flexibility for people to use and adapt code without a huge amount of rewriting.

[!NOTE] A new version of oak needs to be published for these to be available which should be in a little while after I make sure everything is good to go.

kitsonk avatar Feb 04 '24 01:02 kitsonk