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

[Feature request] Pass default handler to customHandlers #54

Closed
cibernox opened this issue Mar 12, 2015 · 9 comments
Closed

[Feature request] Pass default handler to customHandlers #54

cibernox opened this issue Mar 12, 2015 · 9 comments

Comments

@cibernox
Copy link
Collaborator

I'll expose my use case to see if you see this as something it might worth to add.

I have some index routes where I need to perform pagination (and also filtering if a filter=abc query param is received) but also they need to handle coalescedRequests like /posts?ids=1,3,5.

I've defined a custom hander like this one:

this.get('/posts', function(store, request) {
  if (request.queryParams.ids) {
    // mimic default behavior
  } else {
    let results = store.findAll('post');
    let payload = {};
    if (request.queryParams.filter) {
      // do filter
    }
    // bla bla construct meta 
    return payload
  }
});

I thought that a situation where you want to use the default behavior or a slightly modified version of the default behavior, receiving the default handler as a third parameter in that function could be useful.

P.e:

this.get('/posts', function(store, request, defaultHandler) {
  if (request.queryParams.ids) {
    return defaultHandler(store, request);
  } else {
    return myCustomPayload;
  }
});

or

this.get('/posts', function(store, request, defaultHandler) {
  var payload = defaultHandler(store, request);
  payload.meta = { page: 1, timestamp: (new Date()).toString() };
  return payload;
});

Thoughts? I've located the part of the code that has to be changed and seems fairly minimal.

@cibernox cibernox changed the title Pass default handler to customHandlers [Feature request] Pass default handler to customHandlers Mar 12, 2015
@samselikoff
Copy link
Collaborator

defaultHandler being what gets called when there's no second param passed to this[verb]?

In your second case defaultHandler would then just return db.contacts, so you could write

this.get('/posts', function(db, request, defaultHandler) {
  var payload = db.contacts;
  payload.meta = { page: 1, timestamp: (new Date()).toString() };
  return payload;
});

(btw it's db instead of store now)

@samselikoff
Copy link
Collaborator

just to clarify, because the default handler changes based on the second param to this[verb] (undefined, array, string etc.)

@cibernox
Copy link
Collaborator Author

Yes, with defaultHandler being the default handler of the route if no second argument is passed (although a this.get('/posts', 'article', function(db, request, handler) being handler the customized handler given the 2nd argument can also be useful)

In my second example it's not that simple as db.contacts, because the default handler takes care of coalesced requests like /posts?ids=1,3,5, while db.contacts returns all.

@samselikoff
Copy link
Collaborator

still confused...

because the default handler takes care of coalesced requests like /posts?ids=1,3,5, while db.contacts returns all.

bey default handler here are you referring to the first one that you wrote within your own mirage/config.js file?

@samselikoff
Copy link
Collaborator

might be easy if you just gist me the entire /mirage/config.js file, I haven't had a chance to use mirage with an app with lots of filtering/sorting so I'm not familiar with some of these pain points

@cibernox
Copy link
Collaborator Author

I have a few routes that follow the same patterns, so I created a function that generates functions.

import config from '../config/environment';
var defaultPageSize = config.APP.defaultPageSize;

function servePaginatedAndCoalesced(type, { filterField }) {
  let normalizedType = type.underscore();
  let normalizedCollectionType = type.pluralize().underscore();

  return function(store, request) {
    let results = store.findAll(normalizedType);
    let ids = request.queryParams.ids;
    if (ids) {
      return { [normalizedCollectionType]: results.filter(e => ids.indexOf(''+e.id) > -1) };
    } else {
      let total   = results.length;
      let page    = 1;
      let filter  = request.queryParams.filter;
      if (filter && filter.length > 1) {
        filter  = filter.toLowerCase();
        results = results.filter(s => s[filterField].toLowerCase().indexOf(filter) > -1);
      }
      let payload = {};
      let pagedResults = results.slice(0, defaultPageSize);
      payload.meta = { total, page };
      payload[normalizedCollectionType] = pagedResults;
      return payload;
    }
  };
}

  this.get('/schools', servePaginatedAndCoalesced('school', { filterField: 'name' }));
  this.get('/teachers', servePaginatedAndCoalesced('teacher', { filterField: 'surname' }));
  this.get('/staff_members', servePaginatedAndCoalesced('staff_member', { filterField: 'surname' }));
  this.get('/students', servePaginatedAndCoalesced('student', { filterField: 'surname' }));
  // And some more

The real backend will a full featured elastic search filtering, but in mirage I am just creating some endpoints that:

  1. When requested without queryParams, return the first 10 elements in the collection and a meta on the root.
  2. When requested with ids=1,3,5, returns only the elements with those IDs (for enable coalescing)
  3. When receives a ?filter=abc qp and that filter string is long enough (>1 chars) I filter the results by some field.

The reason why I wanted to receive the defaultHandler is to avoid to implement the point 2 myself.

@samselikoff
Copy link
Collaborator

So I think one solution to this would be to define routes that differentiate on query params, for example:

this.get('/schools?ids=:ids', function(store, request) {
  let ids = request.queryParmas.ids;
  // query logic
});
this.get('/schools');  // default

Others have requested this too, e.g. to split up query logic across routes. Would this suit your purposes here? Or are you requesting a generic handler build-in to Mirage that understands ?ids=1,3,5?

@cibernox
Copy link
Collaborator Author

That is good enough for most use cases 👍

@samselikoff
Copy link
Collaborator

Filing this under the "Calling super / expose default route handler" note in the roadmap

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

No branches or pull requests

2 participants