Giter Site home page Giter Site logo

Expose the raw `event.request` about worktop HOT 14 CLOSED

lukeed avatar lukeed commented on August 16, 2024
Expose the raw `event.request`

from worktop.

Comments (14)

lukeed avatar lukeed commented on August 16, 2024 1

Sure, thanks! You don't have to modify anything btw. Your initialization code can look something like this:

import { Router } from 'worktop';
import * as Cache from 'worktop/cache';

const API = new Router;

// ...

addEventListener('fetch', event => {
  let { pathname } = new URL(event.request.url);
  if (pathname === '/ws') event.respondWith(fetch(event.request));
  else Cache.reply(API.run)(event);
});

from worktop.

 avatar commented on August 16, 2024 1

I like the idea of passing the original request as request.raw so that you always have access to it.

For my use case I want to access the original request body reader, but that's currently not possible with Worktop without cloning the request.

This way you can take advantage of the worktop features but still fall back to original request handling where you need to.

The alternative is to build out 100% of functionality, which is maybe a good eventual goal, but until then request.raw may be a necessity.

from worktop.

lukeed avatar lukeed commented on August 16, 2024 1

This is achieved through #83 and will be available as worktop@next for the time being.

from worktop.

lukeed avatar lukeed commented on August 16, 2024
function handler(req, res) {
  var request = new Request(req.url, req);
  // ...
}

from worktop.

lukeed avatar lukeed commented on August 16, 2024

You can proxy WS just fine, there's even a worktop/ws submodule that handles this for you.

The entire framework works by passing a Response directly to the event.respondWith method. The only difference is that worktop adds extra avenues for you to creating/building up a Response

from worktop.

dhrubabasu avatar dhrubabasu commented on August 16, 2024
import {Router, listen} from 'worktop';

const API = new Router();

API.add("POST", "/", async (request, response) => {
  // @ts-ignore
  const req = new Request("https://httpbin.org/post", request)

  return await fetch(req)
})

listen(API.run);

Raw response:

{
  "args": {},
  "data": "{\n\t\"kek\": \"kek\"\n}",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "17",
    "Content-Type": "application/json",
    "Host": "httpbin.org",
    "User-Agent": "[CENSORED]",
    "X-Amzn-Trace-Id": "[CENSORED]"
  },
  "json": {
    "kek": "kek"
  },
  "origin": "[CENSORED]",
  "url": "https://httpbin.org/post"
}

With worktop:

{
  "args": {},
  "data": "function () { [native code] }",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "29",
    "Content-Type": "application/json",
    "Host": "httpbin.org",
    "User-Agent": "[CENSORED]",
    "X-Amzn-Trace-Id": "[CENSORED]"
  },
  "json": null,
  "origin": "[CENSORED]",
  "url": "https://httpbin.org/post"
}

from worktop.

lukeed avatar lukeed commented on August 16, 2024

Oh sorry, that's how it was in a previous version, before req.body became a function.

Instead, it's this:

const request = new Request(req.url, {
  ...req, body: await req.body.arrayBuffer(),
})

Playground

from worktop.

lukeed avatar lukeed commented on August 16, 2024

@dhrubabasu Did this work for you?

from worktop.

dhrubabasu avatar dhrubabasu commented on August 16, 2024

@lukeed It worked for the httpbin example but it doesn't appear to be working for websockets. Here's what I'm trying:

export const passThroughHandler: Handler = async (request, _) => {
  return fetch(
    // @ts-expect-error
    new Request(request.url, {
      ...request,
      body: await request.body.arrayBuffer(),
    }),
  );
};

API.add('GET', '/ws', passThroughHandler);

The result with the above worker:

% wscat -c "wss://example.com/ws"
error: Unexpected server response: 500

from worktop.

lukeed avatar lukeed commented on August 16, 2024

What is your origin receiving?

from worktop.

dhrubabasu avatar dhrubabasu commented on August 16, 2024

I haven't had time to dive into this further but wanted to post a workaround. I'm using worktop/cache so I modified it like this:

export function reply(handler: ResponseHandler): FetchHandler {
  return (event) => {
    if (['/ws'].includes(new URL(event.request.url).pathname)) {
      event.respondWith(fetch(event.request));
    } else {
      event.respondWith(
        lookup(event).then((previous) => {
          return (
            previous ??
            handler(event).then((response) => {
              return save(event, response);
            })
          );
        }),
      );
    }
  };
}

I'll try to put together a minimal repo this weekend to verify if there is an issue with worktop.

from worktop.

lukeed avatar lukeed commented on August 16, 2024

My main hesitation here is that exposing a req.raw property makes it possible for you/users to access the same body multiple ways, which would throw an error. For example:

API.add('POST', '/demo', async (req, res) => {
  let foo = await req.body();
  // ^ success

  let bar = await req.body();
  // ^ this already throws
  //  but it's more obvious why

  let baz = await req.raw.text();
  // ^ throws, and not as obvious

  // also true for this sequence:
  await req.raw.text();
  await req.body(); // throws
});

The only valid way to access it twice would be to do this:

API.add('POST', '/demo', async (req, res) => {
  let copy = req.raw.clone();
  let input1 = await copy.text();

  let input2 = await req.body();
});

... which is fine, but is assumed knowledge & becomes the dev's responsibility.


The other mildly annoying thing is that req.cf and req.raw.cf would be identical. It's fine, but multiple ways to do the same thing kinda bug me 😅

Thoughts?

from worktop.

dhrubabasu avatar dhrubabasu commented on August 16, 2024

Honestly, I think the snippet you posted above is good enough. If you have to access the raw event.request, you're doing something that's not in the norm.

addEventListener('fetch', event => {
  let { pathname } = new URL(event.request.url);
  if (pathname === '/ws') event.respondWith(fetch(event.request));
  else Cache.reply(API.run)(event);
});

I think it should be documented though, perhaps under Advanced?

from worktop.

janat08 avatar janat08 commented on August 16, 2024

Couldn’t a proxy be used instead since then it’s no longer a function but a value ready for consumption which I think could take on form function if required for backwards compatibility.

from worktop.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.