Welcome! We notice you're using an outdated browser, which will result in a degraded experience on this site. Please consider a modern, fully supported browser.

webbureaucrat

The articles are just window-dressing for code snippets I want to keep.

Binding FetchEvent Using Properties and Constructors

Having successfully bound ExtendableEvent, I can now work on inheriting this interface for FetchEvent. Along the way, I'll install bs-fetch as a BuckleScript dependency and bind to JavaScript properties.

Installing bs-fetch

I've already bound ExtendableEvent, but according to the FetchEvent documentation, I need a couple more types before I can bind FetchEvent. The property preloadResponse depends on the Response type, and the property request depends on the Request type. These types are out of scope for me because I'm trying to implement the Service Worker Api, whereas Request and Response are a part of the Fetch API. Fortunately for me, there's already a binding for the Fetch API in bs-fetch. Installation is very simple.

  1. Run npm install bs-fetch.
  2. Add "bs-fetch" to the list of bs-dependencies in the bsconfig.json.

After that, we should be able to use bs-fetch.

Initializing the type and binding to a JavaScript constructor

I have a controversial hottake in functional programming--I love creating a bunch of short files. A lot of functional programmers pride themselves in how little they can fit into a single file, but personally, while I love how succinct functional languages are, I still do not like to scroll, so I am going to start by creating a new file specificlly for this type and call it FetchEvent.re.

One benefit of having a bunch of short files is it makes it easier to manage a bunch of open statements without making a mess or creating ambiguities, so I'm going to open two modules I'm dependent on.

open ExtendableEvent;
open Fetch;

Next, I'm going to initialize my new type using the same subtyping technique we used in my first ReasonML series.

type _fetchEvent('a);
type fetchEvent_like('a) = extendableEvent_like(_fetchEvent('a));
type fetchEvent = fetchEvent_like(Dom._baseClass);

This effectively makes fetchEvent a subtype of extendableEvent, so it can use extendableEvent's waitUntil method that we defined in a previous blog post.

Lastly, for this section, I'm going to bind to the constructor for this type (even though the constructor is almost never called directly). By convention, this function is called make.

[@bs.new] external make : fetchEvent = "FetchEvent";

Binding to JavaScript object properties in ReasonML

At this point, I'm just moving straight down the page of the FetchEvent documentation, which brings me to the "Properties" section. I couldn't find anything on binding properties in the ReasonML documentation. Fortunately, the BuckleScript documentation had the syntax I needed. Basically, each property is a function that takes an instance of my object, like so:

/* properties */
[@bs.get] external clientId: fetchEvent => string  = "clientId";
[@bs.get] external preloadResponse: fetchEvent => Js.Promise.t(Response.t) =
  "preloadResponse";
[@bs.get] external replacesClientId: fetchEvent => string = "replacesClientId";
[@bs.get] external resultingClientId: fetchEvent => string =
  "resultingClientId";
[@bs.get] external request: fetchEvent => Request.t = "request";`

Note that the Request.t and Response.t types are available to us directly because we opened Fetch earlier. Otherwise, we would have had to preface those references with Fetch..

Finishing up by binding methods and exposing t

In continuing working my way down the documentation page, I see there are just two methods for the type, and one of them is built into the supertype ExtendableEvent. We can implement this the same way we implement the properties, but with [@bs.send] to tell BuckleScript to emit a function binding instead of a property binding.

[@bs.send] external respondWith: fetchEvent => Js.Promise.t(Response.t) =
  "respondWith";

// also inherits waitUntil from ExtendableEvent.

Lastly, unlike ExtendableEvent, I expect my library users to reference FetchEvent directly, so let's be nice and expose a t reference.

type t = fetchEvent;

This makes it easy for users to reference our type as FetchEvent.t.

In Conclusion

That's good enough for tonight. Right now I assume I now have a usable FetchEvent, thought I still need to learn to actually test this stuff. I'm optimistic about this binding project. I think if I bind just another couple of types I'll have enough to make a real ServiceWorker in ReasonML.

I write to learn, so I welcome your constructive criticism. Report issues on GitLab.

← Home