-
-
Notifications
You must be signed in to change notification settings - Fork 406
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
EmberData | deprecate legacy finder support #964
base: master
Are you sure you want to change the base?
EmberData | deprecate legacy finder support #964
Conversation
We agreed at the RFC Review meeting today to move this to exploring. There's still a little bit more work to done before we accept. |
It seems that this would reduce DX quite a lot? Loading a record currently: return this.store.findRecord('user', 1); Loading a record after this RFC: import { findRecord } from '@ember-data/json-api/request';
const result = await this.store.request(findRecord('user', '1'));
const user = result.content.data;
return user; Maybe I'm missing some of the benefits, but I'm concerned this change would push many users away from ember-data, which judging only by the number of NPM downloads might already be at a low point (fewer downloads than other addons, e.g., |
I think this example is flawed both because you aren't awaiting the promise, e.g. the correct code snippet is: const user = await this.store.findRecord('user', '1');
return user; And because (1) 50% of Ember apps dropped EmberData because of the inflexibility that the above example has and (2) a lot of the remaining users (finger in the wind I'd guess ~50%) don't use const user = await this.store.findRecord('user', '1', { reload: true });
return user; The change here allows you to trust the cache in a way these apps never could. Especially once Next, consider what's going on here: const result = await this.store.request({
url: '/api/v1/users/',
headers: new Headers([['Accept', 'application/vnd.api+json']])
}); (The builder import is just an abstraction so you don't have to think about building urls and fetch options unless you actually need to). This is far more succinct and ergonomic than what most apps have historically done to work around all the problems with adapters: const user = await this.store.findRecord('user', '1', {
reload: true,
adapterOptions: { use: 'json:api', namespace: 'api/v1' }
}); ^ and then a series of very hacky things in adapters to try to make those Which incidentally brings me to the point that this older mechanism requires you to maintain a complex mental model and adopt thousands of lines of confusing adapter/serializer logic in your codebase. The couple of lines above in the call to Finally, you have to consider what this line is actually giving you: const user = result.content.data; let's break this down:
So we see, the request point dx is largely improved. For the response the only real difference here is that you have this expressive and highly useful access to all of the information you might want. You trade
ember-truth-helpers is a pretty special case, most addons are not installed by 100% of ember apps like it is.
ember-source is ~135k/week and ember-data is ~95k/week and both have been very stable at those download levels for the last year. I actually suspect we're trending up to, a lot of apps seem to have made the jump to 5.x or adopted 5.x despite the massive set of deprecations in 4.x A final thought: I'm reminded of the transition to strict templates and the (similar to yours) sentiments that no one would want to make the transition: e.g. why |
Thanks for the explanation!
If it makes any difference, I've worked in about a dozen of Ember applications using both REST and JSON API adapters and I've never ran into that issue or had to add
I did use
It's good the raw response is now accessible but I'm not sure how used it will be.
For failed requests, including > 500, the
As you can see, it's more cumbersome as there's more ceremony for a simple request. You mentioned 50% of users struggled with ember-data I should add that
to
Finally, this is just a nit - I dislike this function call as an argument. I'm not sure if this was done to keep the number of lines closer to current implementation or to have the example shorter:
vs
Thank you for working to improve |
There's kinda a few points to make on this.
import { findRecord } from '@ember-data/json-api/request';
model(params) {
return this.store.request(findRecord('user', params.id));
} The utility of this becomes even more clear once you look at how applications actually use EmberData. Very few applications in my experience rely on the simple form of For For For Further , with
On the contrary, you are pointing out exactly why we do want to do this. You've already mentioned two of the primary reasons to do this. (1) the need otherwise to customize adapters using brittle heuristics that are assumed to be universal and rarely are. And doing so using very hacky work arounds to attempt to thread enough context to them to achieve what was needed. And (2) access to errors. If you want access to errors then you want the response content, not the record. On Create/UpdateI've set this into a different section because it honestly deserves its own analysis. Is the below verbose? Yes. Its also though the most verbose it will ever be. import { recordIdentifierFor } from '@ember-data/store';
import { updateRecord, serializePatch } from '@ember-data/json-api/request';
user.name = 'Chris';
const request = updateRecord(user);
request.body = JSON.stringify(
serializePatch(
store.cache,
recordIdentifierFor(user)
)
);
await store.request(request); Importantly, this does 100% of the work that adapters, serializers and custom-fetch did before. In other words, we've replaced a thousand of lines of complex logic with a couple of simple assignments. Which is nice, it makes the mental model far easier. Especially because I've yet to encounter an app for which Nearly every app I've worked on has multiple services or model methods dedicated to working around the limitations of Especially because now you can save only what you wanted to save, you don't have to do crazy hacks in order to support saving a single attribute or just a couple of attributes, you don't even need a record to do a save, and you can even control the timing of ui updates, deciding whether to be optimistic or pessimistic. Even better, less need for crazy rollbackAttributes work arounds for failed saves or when leaving a component or route. But can we do better? Sure. We intentionally gave the maximally verbose example because that is the solution that solves the problems that have caused most people to bail. Here's the minimal one: import { updateRecord } from '@ember-data/json-api/request';
user.name = 'Chris';
await store.request(updateRecord(user)); As opposed to (the non @ember-data/model way) of user.name = 'Chris';
await store.saveRecord(user); The only real difference is that there is an import. As far as the If for your app you'd like to hide things just a bit more, then either use a service to build the fetch options or use builders that accept the store as an argument. For instance: import { saveRecord, findRecord } from 'my-app/builders';
const user = await findRecord(store, 'user', '1');
user.name = 'Chris';
await saveRecord(store, user); Or if you want, the service approach: export default class Store extends StoreService {
findRecord(identifierOrType, idOrOptions, maybeOptions) {
const result = await this.request(findRecord(idenfitiferOrType, idOrOptions, maybeOptions));
return result.content;
}
} |
The learning team reviewed this at today's meeting and have a couple questions.
This will help us figure out priorities and work order. Advancement PR: #942 We also reviewed the to-do list for making Request Service. I will break it into issues, and will help ask for contributors. |
It would be great if the RFC had concrete examples of how things are currently done or things that can't be done today and how it would done if the RFC is implemented. Just saying adapters are complex or confusing doesn't seem sufficient. |
@jenweber RE
For the first, the blocker is rewriting the guides and tutorial. |
@btecu that was the request RFC. Many years ago at this point. But also
I think saying what I have is sufficient. Replacing a thousand lines of code that no one understands or can debug with a few lines of code that everyone can understand and debug doesn't seem to need to say much more than that. |
Status update here is: ember-data and learning are working to improve the documentation story for the features that replace this feature before we want to move forward with actively deprecating it. |
checklist for advancing this
|
This is expected to move forward after the newer async-relationship support lands. |
We haven't landed all the pre-flight work and relationship work is still in-progress but its not a requirement for a design that the final implementation details are done before it lands, so moving to push this ahead provided we add details around the new We should also call out that we will need new docs for linksMode and a new guides section around "how to work with relationship/pagination links when your API does not provide them for you" |
@runspired Should this be merged or have the FCP label removed? |
Rendered