tgvashworth / fetch-engine

A smart request-making library
24 stars 6 forks source link

Define plugin composition #3

Closed tgvashworth closed 9 years ago

tgvashworth commented 9 years ago

Issue #1 threw up a question about combining plugins, or only applying them to a subset of requests. It's desirable that an existing composition can be further composed.

Each plugin needs to be able to 'drop' the request, and prevent it from going any further. This lends itself well to the 'then' pattern that JSers have learnt from Promises. Example to follow...

tgvashworth commented 9 years ago

An example, in slightly verbose JS...

class Some {
  constructor(v) {
    this.value = v;
  }

  then(f) {
    return f(this.value);
  }
}

class None {
  then() {
    return this;
  }
}

const Maybe = {
  Some: x => new Some(x),
  None: new None()
};

// Compose two functions that both take a request, but only *might* pass
// the request on.
// compose :: (a -> Maybe b) -> (b -> Maybe c) -> (a -> Maybe c)
const Thenable = {
  compose: (f, g) => x => g(x).then(f),
  composeMany: (...fs) =>
    fs.reverse().reduce((g, f) => Thenable.compose(f, g))
};

const filterRequest = r => (
  r.path.startsWith('/boop')
    ? Maybe.Some(r)
    : Maybe.None
);

const isInFlight = r => false; // TODO!
const dedupeRequest = r => (
  isInFlight(r)
    ? Maybe.None
    : Maybe.Some(r)
);

const addAuthHeaders = r => (
  r.headers = { Authorization: 'yes, please' },
  r
);

const boopDedupe = Thenable.composeMany(addAuthHeaders, dedupeRequest, filterRequest);

Head over here to see it in action.

tgvashworth commented 9 years ago

While this is conceptually compatible with Promises, it might as well just be Promises. Will work on a sketch.

tgvashworth commented 9 years ago

Closing, as this is now better addressed in #1.