-
Notifications
You must be signed in to change notification settings - Fork 27.4k
feat($resource): expose $promise and $response in promise-based api #2060
Conversation
Expose $then and $resolved properties on resource action return values which allow checking if a promise has been resolved already as well as registering listeners at any time of the resource object life-cycle. This commit replaces unreleased commit f3bff27 which exposed unintuitive $q api instead and didn't expose important stuff like http headers.
PR Checklist (Minor Feature)
|
Thanks for the review, Igor! Lets discuss returning value vs http response object from the promise. I chose to return value in this PR because:
If it were to return http response, we will have to use something like In general, to answer that question, we should ask ourselves: a promise of what do we want to provide in resource.$promise? I view it as a promise of initial data because it's the abstraction layer that $resource module provides. It can also be viewed as a promise of underlying http response, but I think in this case it should be named $httpResponsePromise to avoid confusion (of abstraction layers). Or $httpPromise at least. What do you think? What also bothers me right now is that the $promise is tied to initial request. What should happen when the user calls $get() on the resource to update it? Maybe we should replace it with new promise (it could easily get complicated if several requests will be in flight at the same time)? Or leave it as is and just don't bother? The tests and docs will be updated as soon as we get a decision about this. |
@ashtuchkin I'm +1 with you in wishing that the promise on I've also always found there to be some weirdness with this whole thing wrt. what happens what you call instance methods like If totally breaking the API was an option my vote would be to:
|
@ashtuchkin you make some good arguments, but here are the constraints that I'm working with:
@jonbcard as described above, there must be a way to get hold of the http info. |
@IgorMinar yeah -- I get where you're coming from on this, but it my own head it makes more sense just to expose important information (e.g. headers) as a property of a resource response rather than leaking the Edit: I guess what I just described isn't much different from what you're looking for. It just a question of whether a resource object or the http response is the top level in the object hierarchy provided to the callback. |
@jonbcard fair enough. I'm starting to get convinced. |
@IgorMinar That's good. Maybe @ashtuchkin is already close on this, then, if we can fully convince you. :). As @ashtuchkin brought up, I also think there is still an open question about how to define what is supposed to happen to an existing Resource's promise properties when you call an instance method on it. I didn't look carefully at this PR but my assumption is that they will get overwritten. Whatever behaviour happens here, can we make it well defined as part of the doc and spec? Its important especially if you want to do something like this:
If we're overwriting the resource $resolved/$promise properties, the form would quickly disappear while the save action happens then reappear when completed. If people at least know that this is expected, they can at least code around it / avoid using |
@jonbcard we should not overwrite the props as that would defeat the main usecase for $resolve which is what you captured in the example above. breaking the action method api is very tempting now.. :) |
@IgorMinar You talking about changing the instance method API (e.g. @IgorMinar @ashtuchkin Please let me know if there is anything I can do to help out on this. (e.g. if a new PR would help you contemplate the change). |
Guys I've updated the PR, please see. Main changes:
I've also updated the documentation, please check below. Maybe we need to add examples, what do you think?
|
Rebased to master. |
I discussed this with the rest of the team today and I'd like to explore one more path: what if the promise api always resolved to resource instances only and no http anything would be exposed anywhere in the resource api, except for the place where you define your resource. In the resource definition you'd register an extra http transform that would get access to the http primitives and it would be job of this transform to construct a new resource instance or update an existing one. that way the http stuff is encapsulated in the resource definition and doesn't leak into the code that uses the resource instances (controllers or services). |
I totally agree. That way we can simplify the code even more. Would you like me to do that? Do you want to keep the other logic as it is done now? |
Yes please. Can you give it a shot? Make the initial changes and then commit it as a new commit into this branch, so that I can see how things changed from the current version. |
Would it be possible to make the transformers support both transformer prior to sending data and to transform the data coming back? I wrote a rails resource factory to allow us to support root wrapping and camel/underscore based naming translation and the key part of that was adding transformers/interceptors to perform that logic. The other motivation was to expose promises but I like what you guys are doing here with promises better where the query/get would return an object with the promise available on it and the instance methods would return the promise. Returning the object from the query/get is something we are going to be changing in my project because it's definitely more convenient for those to be a reference to what gets populated on success. |
+1 to transforming data before send / receive. When you construct / update a resource instance it would also be really useful to define methods that could act on that resource data. |
+1, this latest version is exactly what I'm looking for. |
@ashtuchkin are you still working on that ? |
Change promise API to be more consistent with other parts of Angular and with abstraction layers. Major changes: * Exposed instance.$promise as the most recent server interaction promise. * $promise is resolved with resource instance, not http response object. This is more consistent to success/error callbacks and route when/resolve clause. * Changed instance.$resolved to be true all the time after first server interaction finished. * Removed instance.$then and response.resource as they are not needed anymore. * Instance actions now return $promise to allow easy chaining. Tests & Docs are updated accordingly.
Sorry for the delay, guys.
Let me know how you want to proceed with this PR. @jgrund I agree that instance methods would be a great addition, making ngResource closer to a full-blown Model component, but I believe it's a scope for another PR. |
@ashtuchkin I agree, hope to see these changes move forward so methods can be added after. |
If I understand this change correctly; Keep up the great work! |
@klebba Thank you! Correction: it will be |
That makes sense, great! |
fyi we've rebased this PR and are experimenting with some more changes via PR #2607 |
Merged in #2607 - thanks @ashtuchkin ! |
This is a WIP to show a possible $resource promise-based api discussed in dba6bc7
Main changes:
$promise
and$response
(http response) are exposed on resource instance object in addition to$then
and$resolved
.$route.when()
.Arguably,
$then
and$response.resource
are not needed anymore, what do you think?