Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hookable StateSources #118

Closed
dariocravero opened this issue Feb 10, 2015 · 17 comments
Closed

Hookable StateSources #118

dariocravero opened this issue Feb 10, 2015 · 17 comments

Comments

@dariocravero
Copy link
Contributor

Hi all,

We have a use case in which we may need our own StateSource implementation as our HTTP services behave slightly different than normal :'(.

stateSourceMixin doesn't really give us an option to define our own and seamlessly plug it in.

Would it be desirable if we allow for any StateSource definition to be pluggable? This would allow for specific sources that wouldn't really suit a general audience but a smaller group and can distribute it then.

Alternatively we can mimic createStateSource but it feels wrong to do that as it kind of kills the canonical way of doing it with Marty...

Thoughts?

@oliverwoodings
Copy link
Contributor

You can use mixins when declaring state sources:

var FooSource = Marty.createStateSource({
  mixins: [{
    bar: function () {
      alert("waddup foos");
    }
  }],
  baz: function () {
    this.bar();
  }
});

@jhollingworth
Copy link
Contributor

Mixins help you get most of the way there.

That said I've been contemplating introducing Marty.use() which would allow you to register different state source types, e.g.

Marty.use(function (container) {
   container.registerStateSourceType("foo", { ... });
});

var FooSource = Marty.createStateSource({
  type: "foo",
  baz: function () {
    this.bar();
  }
});

Is that the sort of thing you were thinking?

@dariocravero
Copy link
Contributor Author

Thanks both. Our use case requires us dealing with the headers in a different way than the HttpStateSource is doing so now.
In the mixin scenario, would we have to overwrite request for that to work?

@jhollingworth
Copy link
Contributor

Ah, thats a bit more interesting. We should probably provide hooks for the various stages of an http request

@dariocravero
Copy link
Contributor Author

Yeah, we found it a bit confusing that it would actually swallow that... I thought it was just a simplification but if it could be expanded to cater for more flexibility, then good stuff :)

@jhollingworth
Copy link
Contributor

so what bits of would you like to be configurable?

@dariocravero
Copy link
Contributor Author

It's basically not having then dealt with and have fetch's return available.

@jhollingworth
Copy link
Contributor

I'm starting to thing we should just remove that whole block of code. It means theres a little more work in the response but Marty isn't forcing any opinions on the consumer

@dariocravero
Copy link
Contributor Author

👍 💃

@dariocravero
Copy link
Contributor Author

Correct me if I'm wrong but perhaps that bit could be a mixin?

@oliverwoodings
Copy link
Contributor

I actually just experienced the issue you're having myself! I needed to intercept calls to this.request in order to add in cookie headers and also add in generic error handlers for authentication issues. I ended up having to do this:

var HttpStateSource = require("marty/lib/stateSources/http");
var _ = require("lodash");

var httpStateSource = HttpStateSource({
  baseUrl: "afakeurl"
});

_.wrap(httpStateSource.request, function (fn) {
  var args = [].slice.apply(arguments, 1);
  // do something with args here if you need to modify them
  return fn.apply(this, args)
    .catch(function (error) {
        // catch 401's and emit action
    });
});

return httpStateSource;

Obviously less than ideal!

@jhollingworth
Copy link
Contributor

@oliverwoodings so you want some sort of global hook for all requests?

@oliverwoodings
Copy link
Contributor

Either that, or an easy way to wrap the request function

@jhollingworth
Copy link
Contributor

You could have some equivalent to $.ajaxSetup but I do feel a little dirty about about globals

@oliverwoodings
Copy link
Contributor

Yeah I don't think that's the right route to go down.

I think perhaps what this is highlighting is that there is rarely a 'standard' way for people to interact with their API; even if it has a standard structure (such as a REST API) things like authentication and error handling are always going to be different. Are mixins really powerful enough to enable to level of extending that people might want to do on state sources? Perhaps instead we need the concept of 'extending' a state source, in the same way that in Backbone you 'extend' the model?

@jhollingworth
Copy link
Contributor

I've just implemented middleware for the HTTP state source which should solve your problems. This API isn't final yet but the idea is you can register hooks for before an after an http request is made

var HttpStateSource = require('marty/http/stateSource');

HttpStateSource.use({
  priority: 1,
  before: function (req) {
    req.headers['Foo'] = 'bar';
  },
  after: function (res) {
    return Immutable.fromJSON(res.json());
  }
});

I've removed the bit of code where I throw an error if the status code >= 400 completely. However I've kept the code for converting the body to and from JSON but its now in middleware so it can be removed if you don't want it

var HttpStateSource = require('marty/http/stateSource');
var ParseJSON = require('marty/http/middleware/parseJSON');

HttpStateSource.remove(ParseJSON);

The API isn't finalised so let me know if there are things that can be done to improve it

@jhollingworth jhollingworth mentioned this issue Feb 19, 2015
50 tasks
@jhollingworth
Copy link
Contributor

Hooks (new name for middleware) are now implemented in v0.9

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants