Skip to content

Commit

Permalink
feat: cacheTime / staleTime
Browse files Browse the repository at this point in the history
  • Loading branch information
prc5 committed Dec 9, 2024
1 parent 7995223 commit aaac03d
Show file tree
Hide file tree
Showing 38 changed files with 327 additions and 1,014 deletions.
2 changes: 1 addition & 1 deletion documentation/docs/core/request.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ const request = client.createRequest()({
endpoint: "/some-endpoint",
retry: 2,
cancelable: true,
cacheTime: 20000,
staleTime: 20000,
cacheKey: "users",
deduplication: true,
});
Expand Down
17 changes: 9 additions & 8 deletions documentation/docs/guides/01-basic/global-defaults.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ sidebar_label: Global Defaults

### Use global defaults for request

Adding global configs can significantly limit application setup. For the greatest flexibility in configurations created for larger and more complex applications,
global configs are added through callbacks based on request data. This allows us the flexibility to, for example,
make one default configuration for requests using the get method and another default config for the requests using other methods.
Adding global configs can significantly limit application setup. For the greatest flexibility in configurations created
for larger and more complex applications, global configs are added through callbacks based on request data. This allows
us the flexibility to, for example, make one default configuration for requests using the get method and another default
config for the requests using other methods.

Remember: Global configurations are overwritten by request settings, so the options that we set will be applied only to requests that do not have settings specified in their options.
Remember: Global configurations are overwritten by request settings, so the options that we set will be applied only to
requests that do not have settings specified in their options.

---

Expand All @@ -25,7 +27,7 @@ export const client = new Client({ url }).setRequestDefaultOptions((requestOptio
if (requestOptions.method === "GET") {
return {
deduplicate: true,
cacheTime: 20000,
staleTime: 20000,
retry: 3,
};
}
Expand All @@ -41,12 +43,11 @@ export const client = new Client({ url }).setRequestDefaultOptions((requestOptio
### Add your own key mappers

Data and requests made within our library are organized by keys. Each key is generated from request metadata, such as
parameters, query parameters, endpoints, and methods. They can be replaced by the way you choose to segregate and organize data
with your own key mappers.
parameters, query parameters, endpoints, and methods. They can be replaced by the way you choose to segregate and
organize data with your own key mappers.

Note: Keys must be a string value.


```ts
client.setQueueKeyMapper((request) => `Custom_Key_${request.method}_${request.endpoint}`);
client.setAbortKeyMapper((request) => `Abort_Key_${request.method}_${request.endpoint}`);
Expand Down
10 changes: 5 additions & 5 deletions documentation/docs/guides/02-advanced/persistence.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const persistenceStorage: CacheStorageType = {
clear: () => storage.clearAll(),
};

export const client = new Client<{error: ServerErrorType}>({
export const client = new Client<{ error: ServerErrorType }>({
url: "localhost:3000",
cache: (instance) =>
new Cache(instance, {
Expand All @@ -52,7 +52,7 @@ Example below shows the **`IndexedDb`** persistence storage. This way we will us
it to our components. Every time we use the `cache.get(cacheKey)` method, we send a request to our `lazyStorage` and at
the same time return the last data we have, when our promise responds, we will receive an appropriate event that will
propagate the data in our components. This way we are NOT loading whole persistent data into our memory, but only part
of it, not to mention that it will get garbage collected when it's cacheTime expire.
of it, not to mention that it will get garbage collected when it's staleTime expire.

```ts
import { get, set, del, keys } from "idb-keyval";
Expand All @@ -64,7 +64,7 @@ const asyncStorage: CacheAsyncStorageType = {
delete: (key) => del(key),
};

export const client = new Client<{error: ServerErrorType}>({
export const client = new Client<{ error: ServerErrorType }>({
url: "localhost:3000",
cache: (instance) =>
new Cache(instance, {
Expand Down Expand Up @@ -107,7 +107,7 @@ const persistenceStorage: DispatcherStorageType = {
clear: () => storage.clearAll(),
};

export const client = new Client<{error: ServerErrorType}>({
export const client = new Client<{ error: ServerErrorType }>({
url: "localhost:3000",
fetchDispatcher: (instance) =>
new Dispatcher(instance, {
Expand All @@ -134,7 +134,7 @@ const persistenceStorage: DispatcherStorageType = {
clear: () => storage.clearAll(),
};

export const client = new Client<{error: ServerErrorType}>({
export const client = new Client<{ error: ServerErrorType }>({
url: "localhost:3000",
submitDispatcher: (instance) =>
new Dispatcher(instance, {
Expand Down
22 changes: 19 additions & 3 deletions documentation/docusaurus.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { themes as prismThemes } from "prism-react-renderer";
import { Prism } from "prism-react-renderer";
import type { Config } from "@docusaurus/types";
import type * as Preset from "@docusaurus/preset-classic";
import path from "path";
Expand Down Expand Up @@ -280,8 +280,24 @@ const config: Config = {
copyright: `Copyright © ${new Date().getFullYear()} BetterTyped.`,
},
prism: {
theme: { plain: {}, styles: [] },
darkTheme: { plain: {}, styles: [] },
theme: {
plain: {},
styles: [
{
types: ["constructor"],
style: { color: "rgb(255, 255, 255)" },
},
],
},
darkTheme: {
plain: {},
styles: [
{
types: ["constructor"],
style: { color: "rgb(255, 255, 255)" },
},
],
},
},
} satisfies Preset.ThemeConfig,
};
Expand Down
6 changes: 3 additions & 3 deletions examples/adjusted-react-app/src/api/users/users.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ import { client } from "../client";
export const getUser = client.createRequest<{ response: UserModel }>()({
endpoint: "/api/user/:userId",
cache: true,
cacheTime: Time.SEC * 10,
staleTime: Time.SEC * 10,
cacheKey: "customUserDetailsCacheKey",
});

export const getUsers = client.createRequest<{ response: UserModel[] }>()({
endpoint: "/api/users",
cache: true,
cacheTime: Time.SEC * 5,
staleTime: Time.SEC * 5,
});

export const postUser = client.createRequest<{ response: UserModel; payload: PostUserModel }>()({
endpoint: "/api/user",
method: "POST",
cancelable: true,
cacheTime: Time.SEC * 5,
staleTime: Time.SEC * 5,
});

export const patchUser = client.createRequest<{ response: UserModel; payload: PostUserModel }>()({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@ import { client } from "../client";
export const getTea = client.createRequest()({
endpoint: "/api/teas/:teaId",
cache: true,
cacheTime: Time.SEC * 10,
staleTime: Time.SEC * 10,
cacheKey: "teaId",
});

export const duplicatedGetTea = client.createRequest()({
endpoint: "/api/teas/:teaId",
cache: true,
cacheTime: Time.SEC * 10,
staleTime: Time.SEC * 10,
cacheKey: "teaId",
});

export const getTeas = client.createRequest()({
endpoint: "/api/teas",
cache: true,
cacheTime: Time.SEC * 5,
staleTime: Time.SEC * 5,
});

export const createTea = client.createRequest()({
endpoint: "/api/teas",
method: "POST",
cancelable: true,
cacheTime: Time.SEC * 5,
staleTime: Time.SEC * 5,
});

export const updateTea = client.createRequest()({
Expand Down
4 changes: 2 additions & 2 deletions examples/next-app-router/api/users/users.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { client } from "../client";
export const getUser = client.createRequest<UserModel>()({
endpoint: "/api/user/:userId",
cache: true,
cacheTime: Time.SEC * 10,
staleTime: Time.SEC * 10,
});

export const getUsers = client.createRequest<UserModel[]>()({
endpoint: "/api/users",
cache: true,
cacheTime: Time.SEC * 5,
staleTime: Time.SEC * 5,
});

export const postUser = client.createRequest<UserModel, PostUserModel>()({
Expand Down
4 changes: 2 additions & 2 deletions examples/next-app/api/users/users.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { client } from "../client";
export const getUser = client.createRequest<UserModel>()({
endpoint: "/api/user/:userId",
cache: true,
cacheTime: Time.SEC * 10,
staleTime: Time.SEC * 10,
});

export const getUsers = client.createRequest<UserModel[]>()({
endpoint: "/api/users",
cache: true,
cacheTime: Time.SEC * 5,
staleTime: Time.SEC * 5,
});

export const postUser = client.createRequest<UserModel, PostUserModel>()({
Expand Down
6 changes: 3 additions & 3 deletions examples/react-app/src/api/users/users.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ import { client } from "../client";
export const getUser = client.createRequest<{ response: UserModel }>()({
endpoint: "/api/user/:userId",
cache: true,
cacheTime: Time.SEC * 10,
staleTime: Time.SEC * 10,
cacheKey: "customUserDetailsCacheKey",
});

export const getUsers = client.createRequest<{ response: UserModel[] }>()({
endpoint: "/api/users",
cache: true,
cacheTime: Time.SEC * 5,
staleTime: Time.SEC * 5,
});

export const postUser = client.createRequest<{ response: UserModel; payload: PostUserModel }>()({
endpoint: "/api/user",
method: "POST",
cancelable: true,
cacheTime: Time.SEC * 5,
staleTime: Time.SEC * 5,
});

export const patchUser = client.createRequest<{ response: UserModel; payload: PostUserModel }>()({
Expand Down
8 changes: 4 additions & 4 deletions examples/react-app/src/api/visualizer/visualizer.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@ import { client } from "../client";
export const getTea = client.createRequest()({
endpoint: "/api/teas/:teaId",
cache: true,
cacheTime: Time.SEC * 10,
staleTime: Time.SEC * 10,
cacheKey: "teaId",
});

export const duplicatedGetTea = client.createRequest()({
endpoint: "/api/teas/:teaId",
cache: true,
cacheTime: Time.SEC * 10,
staleTime: Time.SEC * 10,
cacheKey: "teaId",
});

export const getTeas = client.createRequest()({
endpoint: "/api/teas",
cache: true,
cacheTime: Time.SEC * 5,
staleTime: Time.SEC * 5,
});

export const createTea = client.createRequest()({
endpoint: "/api/teas",
method: "POST",
cancelable: true,
cacheTime: Time.SEC * 5,
staleTime: Time.SEC * 5,
});

export const updateTea = client.createRequest()({
Expand Down
2 changes: 1 addition & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default {
export const getJestConfig = (): Config.InitialOptions => ({
cache: false,
verbose: true,
testEnvironment: "jsdom",
testEnvironment: "jest-fixed-jsdom",
testTimeout: 1000000,
preset: "ts-jest",
testRegex: [".spec.ts"],
Expand Down
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"@typescript-eslint/rule-tester": "^7.18.0",
"@vitejs/plugin-react": "4.3.0",
"@zerollup/ts-transform-paths": "^1.7.18",
"babel-jest": "^28.1.3",
"babel-jest": "^29.7.0",
"commitlint": "^17.0.2",
"core-js": "^3.6.5",
"cypress": "12.17.4",
Expand All @@ -84,14 +84,14 @@
"eslint-plugin-react-hooks": "4.6.2",
"executioner": "^2.0.1",
"husky": "8.0.1",
"jest": "28.1.3",
"jest-environment-jsdom": "28.1.1",
"jest-extended": "^3.2.0",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"jest-extended": "^4.0.2",
"jest-fixed-jsdom": "^0.0.9",
"jest-watch-typeahead": "^2.2.2",
"jest-websocket-mock": "2.5.0",
"jsdom": "22.1.0",
"lint-staged": "^13.0.1",
"msw": "^2.3.1",
"msw": "^2.6.8",
"next": "14.2.3",
"notistack": "^2.0.5",
"prettier": "^3.2.5",
Expand All @@ -104,8 +104,8 @@
"rollup-plugin-dts": "^6.1.1",
"semantic-release": "^19.0.5",
"terminal-link": "^3.0.0",
"ts-jest": "28.0.5",
"ts-node": "10.9.1",
"ts-jest": "29.2.5",
"ts-node": "10.9.2",
"tsc-alias": "^1.8.8",
"tslib": "^2.3.0",
"typescript": "5.5.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe("Axios Adapter [ Base ]", () => {
expect(spySettle).toHaveBeenCalledTimes(1);
expect(spyReqStart).toHaveBeenCalledTimes(1);
expect(spyResStart).toHaveBeenCalledTimes(1);
expect(spyUpload).toHaveBeenCalledTimes(2);
expect(spyUpload).toHaveBeenCalledTimes(3);
expect(spyDownload).toHaveBeenCalledTimes(3);
expect(spyResponse).toHaveBeenCalledTimes(1);
});
Expand All @@ -91,6 +91,6 @@ describe("Axios Adapter [ Base ]", () => {
onUploadProgress: spyUpload,
});

expect(spyUpload).toHaveBeenCalledTimes(2);
expect(spyUpload).toHaveBeenCalledTimes(3);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import { GraphqlAdapter } from "adapter";
import { GetUserQueryResponse, getUserQuery, getUserQueryString } from "../../constants/queries.constants";
import { LoginMutationVariables, loginMutation } from "../../constants/mutations.constants";

const { startServer, stopServer, resetMocks, mockRequest } = createGraphqlMockingServer();

describe("Graphql Adapter [ Browser ]", () => {
const { startServer, stopServer, resetMocks, mockRequest } = createGraphqlMockingServer();
let client = new Client({ url: "https://shared-base-url/graphql" }).setAdapter(GraphqlAdapter);
let request = client.createRequest<GetUserQueryResponse>()({ endpoint: getUserQuery });
let mutation = client.createRequest<GetUserQueryResponse, LoginMutationVariables>()({
let request = client.createRequest<{ response: GetUserQueryResponse }>()({ endpoint: getUserQuery });
let mutation = client.createRequest<{ response: GetUserQueryResponse; payload: LoginMutationVariables }>()({
endpoint: loginMutation,
});

Expand All @@ -19,8 +20,8 @@ describe("Graphql Adapter [ Browser ]", () => {

beforeEach(() => {
client = new Client({ url: "https://shared-base-url/graphql" }).setAdapter(GraphqlAdapter);
request = client.createRequest<GetUserQueryResponse>()({ endpoint: getUserQuery });
mutation = client.createRequest<GetUserQueryResponse, LoginMutationVariables>()({
request = client.createRequest<{ response: GetUserQueryResponse }>()({ endpoint: getUserQuery });
mutation = client.createRequest<{ response: GetUserQueryResponse; payload: LoginMutationVariables }>()({
endpoint: loginMutation,
});

Expand Down Expand Up @@ -49,7 +50,7 @@ describe("Graphql Adapter [ Browser ]", () => {
it("should make a request with string endpoint", async () => {
const expected = mockRequest(request, { data: { username: "prc", firstName: "Maciej" } });

const { data, error, status, extra } = await client.createRequest()({ endpoint: getUserQueryString }).send();
const { data, error, status, extra } = await client.createRequest()({ endpoint: getUserQueryString }).send({});

expect(expected.data).toStrictEqual(data);
expect(status).toBe(200);
Expand Down Expand Up @@ -145,7 +146,8 @@ describe("Graphql Adapter [ Browser ]", () => {
const timeoutRequest = request.setOptions({ timeout: 50 });
mockRequest(timeoutRequest, { delay: 20 });
await timeoutRequest.send();
expect(instance.timeout).toBe(50);
// @ts-ignore TODO: check this
expect(instance?.timeout).toBe(50);

window.XMLHttpRequest = xml;
});
Expand Down
Loading

0 comments on commit aaac03d

Please sign in to comment.