Hacker News new | ask | show | jobs
by franciscop 1559 days ago
I've been following Bunny (BunnyCDN/Bunny.net) for a while and love what they are doing. Couple of suggestions:

• Every code snippet should be copy/pasteable (and work well), that article might be the entry point to what many are doing.

• I have this feeling this is following Cloudflare's Workers style of `addEventListener('fetch', eventHandler);`. I need to write a 500-word essay on that, but the short version is that I strongly believe that it'd be way better for their clients if the client could just do `export default async function handleDns(event) { ... }` instead of having a global (what?) context where there's a function unattached called `addEventListener` and you need to know it's for `"dns"` (is there even other possibility here?) and that the respondWith() only accepts a promise, which is not common (it's more common to accept an async fn which then becomes a promise). Compare these two snippets, current and with my small proposal:

    // Current API:
    addEventListener('dns', event => {
      event.respondWith(handleRequest(event.request));
    });

    function handleRequest(request) {
      return new TxtRecord('Hello world!, 30);
    }

    vs

    // Potential/suggested API:
    export default function handleDns(event) {
      return new TxtRecord('Hello world!, 30);
    }
This way it's easier to write, to reason about, to test, etc. It's all advantages from the client point of view, and I understand it's slightly more code from Bunny's point of view but it could be done fairly trivially on Bunny's end; they could just wrap the default export with this code on their infra level, simplifying and making dev lives a lot easier:

    // Wrapper.js
    import handler from './user-fn.js';

    addEventListener('dns', event => {
      if (typeof handler === 'function') {
        event.respondWith(handler(event));
      } else {
        // Could support other basic types here, like
        // exporting a plain TxtRecord('Hello', 30);
        throw new Error('Only handler functions supported now');
      }
    });
3 comments

> I strongly believe that it'd be way better for their clients if the client could just do `export default async function handleDns(event) { ... }`

I'm the tech lead of Cloudflare Workers and you're absolutely right about this. We actually introduced such a syntax as an option a while back and are encouraging people to move to it:

https://blog.cloudflare.com/workers-javascript-modules/

Your argument is exactly one of the reasons for this. The more general version of the argument is that it enables composability: you can take a Worker implementation and incorporate it into a larger codebase without having to modify its code. This helps for testing (incorporating into a test harness), but also lets you do things like take two workers and combine them into one worker with a new top-level event handler that dispatches to one or the other.

Thanks! This article is pretty much what I had in mind and exactly my 500-words argument! I don't know how I missed it. This is def one of the things that made me think Cloudflare Workers were not so polished. Are you hiring? I've got many more ideas where this came from :)
Always. Send me an email, kenton at cloudflare.
We're hiring too. You can help us make this amazing!
That was actually the original idea, then for compatibility reasons, we decided to take this path initially. We are exploring adding fallback support as well, given that it greatly simplifies things and DNS can't really afford to do a whole lot of waiting anyway.
Cut out of my CF worker. Just add more routes as necessary (someone could come up with a DNS vs. HTTP specific router).

  import { Router } from 'itty-router';
  import { exportedObject } from './some/other/file';

  const router = Router();

  router.get('/update', async (request: Request, event: FetchEvent) => exportedObject.update(request, event));

  router.all('*', () => new Response('404, not found!', { status: 404 }));

  addEventListener('fetch', (event: FetchEvent) => {
 event.respondWith(router.handle(event.request, event));
  });

I don't even need to start up a http server to do testing of my handlers. I just test the functions directly.