dchester / epilogue

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

Manipulating POST data before create / delete #142

Open moxious opened 8 years ago

moxious commented 8 years ago

Suppose I create endpoints with Epilogue, for a simple model like this:

var Thing = sequelize.define('Thing', {
   x: { type: sequelize.INTEGER },
   y: { type: sequelize.INTEGER }
});

Suppose I then POST to the right endpoint a JSON object like this: { x: 1, y: 2, z: 3 }.

My experience in this scenario is that the endpoint sends back a 500 error with the complaint something like "SQLITE_ERROR: table Things has no column named z"

That makes sense - the question is, what is the recommended approach for manipulating data prior to the database insert step happening? Would this be done via the resource.create.write milestone, by examining the request and modifying it on the wire - or would this be done entirely somewhere else in sequelize?

There are two big use cases I have for this -- one is when a reporting client has more data than I need, and I'd like to accept a subset of that data. (In the example above, I want x and y, he has x, y, z -- I'd like to discard z, without requiring my client to change his format).

The second is when I want an epilogue endpoint to take different formats of json (again, to accommodate clients). I might write some mapping code which would transform the POST body into something else before it hits the sequelize layer.

Any suggestions?

mbroadst commented 8 years ago

@moxious yep you got it, although I would probably use the resource.create.write.before milestone in this case. At that point you can directly modify req.body as well as context.attributes (which will have already automatically pulled known attributes out of the request).

moxious commented 8 years ago

What's the connection between req.body and context.attributes? Is there any documentation that describes how it goes from JSON body to SQL record so I know where to interfere?

I have to do this for a lot of models so I don't want to hand-hack a milestone per model, instead I was looking for the API that would let me access a list of properties that are known on that model, etc.

mbroadst commented 8 years ago

@moxious unfortunately documentation is limited.

context.attributes is generally more useful in things like the ReadController, where the attributes are initially cached from the model associated with the resource here.

in the WriteController, context.attributes are just taken directly from the req.body as shown here.

There are a number of legacy disconnects like this that would be ripe for cleanup. It would be really great if you wanted to submit some documentation about this as you go through the effort.

moxious commented 8 years ago

Ah hah - I think I see. So tentatively, plan of attack might be:

Does that sound reasonable? I'll probably be exploring this over the next week; in the case of something like bullet 3 I may do a pull request when I get there.