id | title | description |
---|---|---|
adrs-adr013 |
ADR013: Proper use of HTTP fetching libraries |
Architecture Decision Record (ADR) for the proper use of fetchApiRef, node-fetch, and cross-fetch for data fetching. |
Using multiple HTTP packages for data fetching increases the complexity and the support burden of keeping said package up to date.
Backend (node) packages should use the node-fetch
package for HTTP data
fetching. Example:
import fetch from 'node-fetch';
import { ResponseError } from '@backstage/errors';
const response = await fetch('https://example.com/api/v1/users.json');
if (!response.ok) {
throw await ResponseError.fromResponse(response);
}
const users = await response.json();
Frontend plugins and packages should prefer to use the
fetchApiRef
.
It uses cross-fetch
internally. Example:
import { useApi } from '@backstage/core-plugin-api';
const { fetch } = useApi(fetchApiRef);
const response = await fetch('https://example.com/api/v1/users.json');
if (!response.ok) {
throw await ResponseError.fromResponse(response);
}
const users = await response.json();
Isomorphic packages should have a dependency on the cross-fetch
package for
mocking and type definitions. Preferably, classes and functions in isomorphic
packages should accept an argument of type typeof fetch
to let callers supply
their preferred implementation of fetch
. This lets them adorn the calls with
auth or other information, and track metrics etc, in a cross-platform way.
Example:
import crossFetch from 'cross-fetch';
export class MyClient {
private readonly fetch: typeof crossFetch;
constructor(options: { fetch?: typeof crossFetch }) {
this.fetch = options.fetch || crossFetch;
}
async users() {
return await this.fetch('https://example.com/api/v1/users.json');
}
}
We will gradually transition away from third party packages such as axios
,
got
and others. Once we have transitioned to node-fetch
we will add lint
rules to enforce this decision.