Skip to content

Commit 81f3276

Browse files
committed
Add guide draft for incremental adoption
1 parent d977397 commit 81f3276

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed
+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Incremental adoption guide for existing projects
2+
3+
Nav links
4+
5+
---
6+
7+
This guide is for existing projects that want to adopt the new APIs of the EmberData incrementally. If you are starting a new project, you should use the [new project guide](./new-project-guide.md).
8+
9+
## Step 1: Upgrade to EmberData 4.12.x
10+
11+
This version of EmberData is the first version that supports the new APIs. It also a LTS version, so you can stay on it for a while. You can refer the [EmberData Compatibility table](https://github.com/emberjs/data/blob/main/README.md#compatibility) to see which version of EmberData is compatible with your Ember version.
12+
13+
## Step 2: Add `Store` service to your application
14+
15+
You would need to create you own store service. Before it was automatically injected by Ember Data.
16+
Here is how you do it:
17+
18+
```ts
19+
// eslint-disable-next-line ember/use-ember-data-rfc-395-imports
20+
import Store from 'ember-data/store';
21+
import { service } from '@ember/service';
22+
import RequestManager from '@ember-data/request';
23+
24+
export default class MyStore extends Store {
25+
@service declare requestManager: RequestManager;
26+
}
27+
28+
```
29+
30+
Notice we still want to import the `Store` class from `ember-data/store` package. You might have a lint rule that says don't do it. You can disable it for this import. The reason we want to import it from `ember-data/store` is because we want to use Ember Data models, serializers, adapters, etc. and alongside we want to start utilizing new APIs.
31+
32+
## Step 3: Add `RequestManager` service to your application
33+
34+
Now let's create our very own `RequestManager` service. It is a service that is responsible for sending requests to the server. It is a composable class, which means you can add your own request handlers to it. In the example below we are adding `LegacyNetworkHandler`, `TestHandler` and `Fetch` handlers.
35+
36+
```ts
37+
import RequestManager from '@ember-data/request';
38+
import Fetch from '@ember-data/request/fetch';
39+
import { LegacyNetworkHandler } from '@ember-data/legacy-compat';
40+
import { CacheHandler } from 'ember-data/store';
41+
import { setBuildURLConfig } from '@ember-data/request-utils';
42+
43+
const TestHandler = {
44+
async request({ request }, next) {
45+
console.log('TestHandler.request', request);
46+
47+
const newContext = await next(request);
48+
49+
console.log('TestHandler.response after fetch', newContext.response);
50+
51+
return next(newContext);
52+
},
53+
};
54+
55+
export default class Requests extends RequestManager {
56+
constructor(args) {
57+
super(args);
58+
this.use([LegacyNetworkHandler, TestHandler, Fetch]);
59+
this.useCache(CacheHandler);
60+
}
61+
}
62+
```
63+
64+
Let's go over the code above:
65+
66+
1. `LegacyNetworkHandler` is the handler that is responsible for sending requests to the server using the old APIs. It will interrupt handlers chain if it detects request using old APIs. It will process it as it used to be doing with Adapters/Fetch/Serializers workflow.
67+
68+
2. Next is `TestHandler`. It is a handler that is responsible for logging requests. It is a quick example of how you can add your own handlers to the request manager. We will take a look at more useful examples later.
69+
70+
3. Lastly `Fetch`. It is a handler that is responsible for sending requests to the server using the new Ember Data APIs. It must be last handler you put in the chain. After finishing request it will enrich handlers context with `response` property. And pass it back to the handlers chain in reverse order. So `TestHandler` will receive `response` property first, and so on if we would have any.
71+
72+
You can read more about request manager in the [request manager guide](./request-manager-guide.md).
73+
74+
## Step 4: Install `@ember-data/json-api`, `@ember-data/request-utils` packages
75+
76+
If you was using JSON:API adapter/serializer for your backend communication, you can use `@ember-data/json-api` package. It is a package that contains predefined builders for JSON:API requests. You can read more about it in the [`@ember-data/json-api` guide](TODO: add link).
77+
78+
If you have different backend format - Ember Data provides you with builders for `REST`(@ember-data/rest) and `ActiveRecord`(@ember-data/active-record).
79+
80+
## Step 5: Off you go! Start using new APIs
81+
82+
Now you can start refactoring old code to use new APIs. You can start with the `findAll` method. It is the easiest one to refactor. Here is how you do it:
83+
84+
```diff app/components/projects/list.ts
85+
+ import { query } from '@ember-data/json-api/request';
86+
87+
loadProjects: Task<void, []> = task(async () => {
88+
- const projects = await this.store.findAll('project');
89+
- this.projects = [...projects];
90+
+ const { content } = await this.store.request(query('project', {}, { host: config.api.host }));
91+
+ this.projects = content.data;
92+
});
93+
```
94+
95+
You most likely would need to add Auth Handler to your request manager to add `accessToken` to your requests.
96+
Let's say you have your `accessToken` in the `session` service. Here is how you can add it to the request manager:
97+
98+
```js auth-handler.js
99+
import { inject as service } from '@ember/service';
100+
101+
export default class AuthHandler {
102+
@service session;
103+
104+
request({ request }, next) {
105+
const headers = new Headers(request.headers);
106+
headers.append(
107+
'Authorization',
108+
`Bearer ${this.session.accessToken}`,
109+
);
110+
111+
return next(Object.assign({}, request, { headers }));
112+
}
113+
}
114+
```
115+

0 commit comments

Comments
 (0)