dchester / epilogue

Create flexible REST endpoints and controllers from Sequelize models in your Express app
846 stars 116 forks source link

Is it possible to get back a resource without associations? #140

Closed shamoons closed 8 years ago

shamoons commented 8 years ago

I have

epilogue.resource({
  model: db.Question,
  endpoints: ['/api/questions', '/api/questions/:id'],
  associations: true
});

So when I hit /api/questions, I get back all the associations with the resources. Is there something I can pass to not get the associations in certain cases? Or should I create a new endpoint:

epilogue.resource({
  model: db.Question,
  endpoints: ['/api/questions2', '/api/questions2/:id']
});
mbroadst commented 8 years ago

@shamoons you could clear out the context.include selectively in a milestone before whichever action you are about to take (or rather the one where you don't want auto association to take place)

For example:

myResource.list.fetch.before(function(req, res, context) {.
   context.include = [];
   return context.continue;
});
shamoons commented 8 years ago

@mbroadst can I do more complex queries with before?

mbroadst commented 8 years ago

@shamoons yes milestones are intended to give you full control over epilogues "flow"

shamoons commented 8 years ago

@mbroadst do you have any code samples with more complex queries? Specifically additional joins?

mbroadst commented 8 years ago

@shamoons you should check out Sequelize directly if you want to get into complex queries. Epilogue simply provides you with sane defaults for the case of rest resources, but when it boils down its just using Sequelize. In the example milestone above I gave you, you can call whatever sequelize method you want and set the context.instance to the result in order to override the default behavior of the route generated by epilogue

shamoons commented 8 years ago

so do:

myResource.list.fetch.before(function(req, res, context) {
   myModel.findAll()... // other stuff goes here
   .then(function(dbRes) {
      context.instance = dbRes
   });
   return context.skip;
});

something like that?

mbroadst commented 8 years ago

exactly, except you'd want to return the continue after the async operation, like so:

myResource.list.fetch.before((req, res, context) => {
   let Model = myResource.model;
   return Model.findAll({ /* other stuff goes here */ })
     .then(result => { context.instance = result; })
     .then(() => context.skip);
   });
});
shamoons commented 8 years ago

Where does myResource come from? is that the myResource = epilogue...?

mbroadst commented 8 years ago

yes

shamoons commented 8 years ago

Can I just use res.json instead of that? Presently, I have

passageResource.update.write.before(function(req, res, context) {
  var passageId;
  passageId = req.params.id;
  return db.Passage.update(req.body.data.passage, {
    where: {
      id: passageId
    }
  }).then(function(dbPassage) {
    return db.PassageLine.destroy({
      where: {
        PassageId: passageId
      }
    });
  }).then(function() {
    var passageLines;
    passageLines = _.map(req.body.data.passageLines, function(passageLine) {
      passageLine.PassageId = passageId;
      return passageLine;
    });
    return db.PassageLine.bulkCreate(passageLines);
  }).then(function(response) {
    context.instance = {};
    return context["continue"];
  });
});

and the API response is:

{
    "message": "internal error",
    "errors": ["Object #<Object> has no method 'setAttributes'"]
}
mbroadst commented 8 years ago

@shamoons oops I miswrote above, if you are going to bypass the existing epilogue behavior you need to return context.skip instead of context.continue

UPDATE: I updated the above posts to make this change, for future readers

shamoons commented 8 years ago

@mbroadst Can I do this for association routes? /api/students/4/workbooks say?

mbroadst commented 8 years ago

@shamoons yes, association routes are just resources created automatically with customized milestones