ponzu-cms / ponzu

Headless CMS with automatic JSON API. Featuring auto-HTTPS from Let's Encrypt, HTTP/2 Server Push, and flexible server framework written in Go.
https://docs.ponzu-cms.org
BSD 3-Clause "New" or "Revised" License
5.68k stars 387 forks source link

BeforeAPIRetrieve hook? #302

Closed olliephillips closed 5 years ago

olliephillips commented 5 years ago

Might there be use cases where we want to further process content before it is retrieved over API. Spellchecks might be trivial examples, but less trivial might include processing shortcodes, (wordpress style) before content is served?

nilslice commented 5 years ago

I'm all for this!

Maybe BeforeAPIResponse or BeforeAPIGet is a more applicable name. I think it's also worth adding a AfternAPIResponse or AfterAPIGet (whichever name you think is better)...

olliephillips commented 5 years ago

Yes, "retrieve" is a bit lame. I like your suggestion of "response". I'll look at this, as I think it may be something I can use in a future project.

nilslice commented 5 years ago

Awesome. Let me know if you need any help. You'll see the default implementations in item.go for the Hookable interface, where these new methods likely need to be.

logicalphase commented 5 years ago

I really like this. One other use case might be for sanitizing, etc.

olliephillips commented 5 years ago

I have BeforeAPIResponse and AfterAPIResponse implemented in contentsHandler(..),contentHandler(..) and contentHandlerBySlug(..) responses. They can be tested to error with 500 and log message.

I need to pass the response data, to make that mutatable, certainly to the BeforeAPIResponse hook, not sure about "After".

Edit : This is done, passed it to both Before and After to keep the API consistent. Maybe there is a usecase for logging or something in After.

However, I need some guidance - there is the matter of "push" to consider. I could take the the above hooks into push function? Or maybe these should be different hooks, for example BeforeAPIPush() and AfterAPIPush? I feel like they would be used in very similar fashion, so wonder whether differentiating is worth it?

Also, what is the correct way to intercept item content in a hook such as BeforeSave (when saving as admin in ponzu server)? I have tried to amend the request form fields directly. And, though I can see the mutation I make, I cannot get them to persist into the database. For example, this does not work for me, despite it following an approach I've seen in the FBScheduler addon:

func (r *Review) BeforeSave(....) error {
 err := req.ParseMultipartForm(1024 * 1024)
 if err != nil {
  log.Println(err)
  return errors.New("problem parsing form")
 }

 // alter data
 val := req.FormValue("title")
 newVal := val + "my text"
 req.Form.Set("title",  newVal)
 return nil 
}

Any assistance on this appreciated.

olliephillips commented 5 years ago

I have pushed commits to my fork on ponzu-dev.

olliephillips commented 5 years ago

Just an update. Where I got to in my thinking is do NOT move the *APIResponse hooks down into push functionality. If something similar where to be added it should be on *APIPush (or similar) so we can choose to replicate functionality in that hook or do something different, as may be required - I don't know.

Is operating on the []byte slice the best way to go here? I can't see another way, and I see omitable uses it, but use to delete keys. I see a bit of danger here if the []byte response is messed up - we won't get build errors nor panics, just bad data at the client.

I have early and rough shortcodes addon - it makes sure the replacements are both escaped and JSON standard encoded, so it is handled, but thoughts appreciated. Should we build in some validation?

I'm still no wiser on the BeforeSave issue I was hitting, however :/

nilslice commented 5 years ago

Hey @olliephillips - sorry for the delay. I've been heads down on some day job work that is keeping me quite busy.

To try and help w/o being able to dedicate much time:

Is operating on the []byte slice the best way to go here?

I didn't see another way at the time, and I'm thinking you have also hit the same bumps I did. I think it's ok... and we have to rely some on the developer to not mess this up themselves. If you have other ideas though, please do share.

I have early and rough shortcodes addon

Excited to see this!

I'm still no wiser on the BeforeSave issue I was hitting, however :/

These hooks are not super complete unfortunately... you will need to make a DB lookup with the ID to get the full type inside the hook. You will then need to modify the instance of that type using values from the req.PostForm, and then do a db.Save (?) to update the record.

This could use a re-visit, as it is not the most polished process...

olliephillips commented 5 years ago

Hey @nilslice. That's great feedback thanks - I expected you were busy - but this gives me a good steer. I can't see another way with []byte slice either, but, on the plus side it makes the hook easier to use and more powerful, which I like a lot. For example with shortcodes I need to know nothing about the item struct nor its fields, I can just run the replacement on the whole JSON response. I think this is the way to go, if we could check the output before send over API that would be perfect. I'll look further into that.

Re beforeSave form issue - I'll look at that soon.

olliephillips commented 5 years ago

Above PR merged to this repo's, ponzu-dev branch. Closing this.