Skip to content
module@warp-drive/core

Function useRecommendedStore() ​

ts
function useRecommendedStore<T extends Cache, Policy extends CachePolicy>(options: StoreSetupOptions<T> & {
  policy: Policy;
}, StoreKlass?: typeof Store): typeof ConfiguredStore;
function useRecommendedStore<T extends Cache>(options: StoreSetupOptions<T> & {
  policy?: undefined;
}, StoreKlass?: typeof Store): typeof ConfiguredStore;
function useRecommendedStore<T extends Cache>(options: StoreSetupOptions<T>, StoreKlass?: typeof Store): typeof ConfiguredStore;

Call Signature ​

ts
function useRecommendedStore<T extends Cache, Policy extends CachePolicy>(options: StoreSetupOptions<T> & {
  policy: Policy;
}, StoreKlass?: typeof Store): typeof ConfiguredStore;

Defined in: warp-drive-packages/core/src/index.ts:280

Creates a configured Store class with recommended defaults for schema handling, reactivity, caching, and request management.

The Setup guide walks through configuring the store with it.

ts
import { useRecommendedStore } from '@warp-drive/core';
import { JSONAPICache } from '@warp-drive/json-api';

export const Store = useRecommendedStore({
  cache: JSONAPICache,
  schemas: [],
});

Adding Stateful Handlers ​

A request Handler is sometimes more than a plain object or class with a request method — it may need access to a stateful dependency such as an Ember service (an auth token, a feature-flags service, an i18n helper, etc.).

A plain class handler that only relies on Ember's @service decorator will not work here on its own: the handler is never instantiated through Ember's container (it's just new'd up), so it has no owner and its @service injections would fail to resolve.

Instead, give handlers a function. It receives the Store instance being configured, which by the time the function runs already has an owner assigned. Use getOwner/setOwner from @ember/owner to transfer that owner onto your handler instance before returning it, exactly as you would when constructing any other DI-aware object outside of the container:

ts
import { getOwner, setOwner } from '@ember/owner';
import { service } from '@ember/service';
import { useRecommendedStore } from '@warp-drive/core';
import type { NextFn } from '@warp-drive/core/request';
import type { RequestContext } from '@warp-drive/core/types/request';
import { JSONAPICache } from '@warp-drive/json-api';

class AuthHandler {
  @service session;

  request<T>(context: RequestContext, next: NextFn<T>) {
    const headers = new Headers(context.request.headers);
    headers.append('Authorization', `Bearer ${this.session.accessToken}`);
    return next(Object.assign({}, context.request, { headers }));
  }
}

export default useRecommendedStore({
  cache: JSONAPICache,
  handlers: (store) => {
    const authHandler = new AuthHandler();
    setOwner(authHandler, getOwner(store)!);
    return [authHandler];
  },
});

The handlers function is invoked lazily and only once per store instance, the first time store.requestManager is accessed, so it is safe to do owner-dependent setup like this inside of it.

Accessing the Store from a Handler's Context ​

If a handler only needs to read something off of the store itself (its cache, or a property/service you've attached to a custom store subclass) rather than an unrelated Ember service, there is a second, simpler option that requires no DI/setOwner wiring at all.

Every request issued via store.request(...) automatically carries the originating store along as context.request.store. Any handler — a plain object, a function-built handler, or a class — can read it directly, without needing the handlers callback form shown above:

ts
import { useRecommendedStore } from '@warp-drive/core';
import type { NextFn } from '@warp-drive/core/request';
import type { RequestContext } from '@warp-drive/core/types/request';
import { JSONAPICache } from '@warp-drive/json-api';

const LoggingHandler = {
  request<T>(context: RequestContext, next: NextFn<T>) {
    // only present when the request was made via `store.request(...)`
    const store = context.request.store;
    if (store) {
      console.log(`[${store.constructor.name}] ${context.request.url ?? ''}`);
    }
    return next(context.request);
  },
};

export default useRecommendedStore({
  cache: JSONAPICache,
  handlers: [LoggingHandler],
});

The trade-off versus the getOwner/setOwner pattern above is that context.request.store is only populated for requests issued via store.request(...); a request made directly against a RequestManager won't have it set unless the caller supplies it explicitly, so a handler relying on it should treat it as optional (as LoggingHandler does above).

Type Parameters ​

T ​

T extends Cache

Policy ​

Policy extends CachePolicy

Parameters ​

options ​

StoreSetupOptions<T> & { policy: Policy; }

StoreKlass? ​

typeof Store

Returns ​

typeof ConfiguredStore

Call Signature ​

ts
function useRecommendedStore<T extends Cache>(options: StoreSetupOptions<T> & {
  policy?: undefined;
}, StoreKlass?: typeof Store): typeof ConfiguredStore;

Defined in: warp-drive-packages/core/src/index.ts:284

Creates a configured Store class with recommended defaults for schema handling, reactivity, caching, and request management.

The Setup guide walks through configuring the store with it.

ts
import { useRecommendedStore } from '@warp-drive/core';
import { JSONAPICache } from '@warp-drive/json-api';

export const Store = useRecommendedStore({
  cache: JSONAPICache,
  schemas: [],
});

Adding Stateful Handlers ​

A request Handler is sometimes more than a plain object or class with a request method — it may need access to a stateful dependency such as an Ember service (an auth token, a feature-flags service, an i18n helper, etc.).

A plain class handler that only relies on Ember's @service decorator will not work here on its own: the handler is never instantiated through Ember's container (it's just new'd up), so it has no owner and its @service injections would fail to resolve.

Instead, give handlers a function. It receives the Store instance being configured, which by the time the function runs already has an owner assigned. Use getOwner/setOwner from @ember/owner to transfer that owner onto your handler instance before returning it, exactly as you would when constructing any other DI-aware object outside of the container:

ts
import { getOwner, setOwner } from '@ember/owner';
import { service } from '@ember/service';
import { useRecommendedStore } from '@warp-drive/core';
import type { NextFn } from '@warp-drive/core/request';
import type { RequestContext } from '@warp-drive/core/types/request';
import { JSONAPICache } from '@warp-drive/json-api';

class AuthHandler {
  @service session;

  request<T>(context: RequestContext, next: NextFn<T>) {
    const headers = new Headers(context.request.headers);
    headers.append('Authorization', `Bearer ${this.session.accessToken}`);
    return next(Object.assign({}, context.request, { headers }));
  }
}

export default useRecommendedStore({
  cache: JSONAPICache,
  handlers: (store) => {
    const authHandler = new AuthHandler();
    setOwner(authHandler, getOwner(store)!);
    return [authHandler];
  },
});

The handlers function is invoked lazily and only once per store instance, the first time store.requestManager is accessed, so it is safe to do owner-dependent setup like this inside of it.

Accessing the Store from a Handler's Context ​

If a handler only needs to read something off of the store itself (its cache, or a property/service you've attached to a custom store subclass) rather than an unrelated Ember service, there is a second, simpler option that requires no DI/setOwner wiring at all.

Every request issued via store.request(...) automatically carries the originating store along as context.request.store. Any handler — a plain object, a function-built handler, or a class — can read it directly, without needing the handlers callback form shown above:

ts
import { useRecommendedStore } from '@warp-drive/core';
import type { NextFn } from '@warp-drive/core/request';
import type { RequestContext } from '@warp-drive/core/types/request';
import { JSONAPICache } from '@warp-drive/json-api';

const LoggingHandler = {
  request<T>(context: RequestContext, next: NextFn<T>) {
    // only present when the request was made via `store.request(...)`
    const store = context.request.store;
    if (store) {
      console.log(`[${store.constructor.name}] ${context.request.url ?? ''}`);
    }
    return next(context.request);
  },
};

export default useRecommendedStore({
  cache: JSONAPICache,
  handlers: [LoggingHandler],
});

The trade-off versus the getOwner/setOwner pattern above is that context.request.store is only populated for requests issued via store.request(...); a request made directly against a RequestManager won't have it set unless the caller supplies it explicitly, so a handler relying on it should treat it as optional (as LoggingHandler does above).

Type Parameters ​

T ​

T extends Cache

Parameters ​

options ​

StoreSetupOptions<T> & { policy?: undefined; }

StoreKlass? ​

typeof Store

Returns ​

typeof ConfiguredStore

Call Signature ​

ts
function useRecommendedStore<T extends Cache>(options: StoreSetupOptions<T>, StoreKlass?: typeof Store): typeof ConfiguredStore;

Defined in: warp-drive-packages/core/src/index.ts:288

Creates a configured Store class with recommended defaults for schema handling, reactivity, caching, and request management.

The Setup guide walks through configuring the store with it.

ts
import { useRecommendedStore } from '@warp-drive/core';
import { JSONAPICache } from '@warp-drive/json-api';

export const Store = useRecommendedStore({
  cache: JSONAPICache,
  schemas: [],
});

Adding Stateful Handlers ​

A request Handler is sometimes more than a plain object or class with a request method — it may need access to a stateful dependency such as an Ember service (an auth token, a feature-flags service, an i18n helper, etc.).

A plain class handler that only relies on Ember's @service decorator will not work here on its own: the handler is never instantiated through Ember's container (it's just new'd up), so it has no owner and its @service injections would fail to resolve.

Instead, give handlers a function. It receives the Store instance being configured, which by the time the function runs already has an owner assigned. Use getOwner/setOwner from @ember/owner to transfer that owner onto your handler instance before returning it, exactly as you would when constructing any other DI-aware object outside of the container:

ts
import { getOwner, setOwner } from '@ember/owner';
import { service } from '@ember/service';
import { useRecommendedStore } from '@warp-drive/core';
import type { NextFn } from '@warp-drive/core/request';
import type { RequestContext } from '@warp-drive/core/types/request';
import { JSONAPICache } from '@warp-drive/json-api';

class AuthHandler {
  @service session;

  request<T>(context: RequestContext, next: NextFn<T>) {
    const headers = new Headers(context.request.headers);
    headers.append('Authorization', `Bearer ${this.session.accessToken}`);
    return next(Object.assign({}, context.request, { headers }));
  }
}

export default useRecommendedStore({
  cache: JSONAPICache,
  handlers: (store) => {
    const authHandler = new AuthHandler();
    setOwner(authHandler, getOwner(store)!);
    return [authHandler];
  },
});

The handlers function is invoked lazily and only once per store instance, the first time store.requestManager is accessed, so it is safe to do owner-dependent setup like this inside of it.

Accessing the Store from a Handler's Context ​

If a handler only needs to read something off of the store itself (its cache, or a property/service you've attached to a custom store subclass) rather than an unrelated Ember service, there is a second, simpler option that requires no DI/setOwner wiring at all.

Every request issued via store.request(...) automatically carries the originating store along as context.request.store. Any handler — a plain object, a function-built handler, or a class — can read it directly, without needing the handlers callback form shown above:

ts
import { useRecommendedStore } from '@warp-drive/core';
import type { NextFn } from '@warp-drive/core/request';
import type { RequestContext } from '@warp-drive/core/types/request';
import { JSONAPICache } from '@warp-drive/json-api';

const LoggingHandler = {
  request<T>(context: RequestContext, next: NextFn<T>) {
    // only present when the request was made via `store.request(...)`
    const store = context.request.store;
    if (store) {
      console.log(`[${store.constructor.name}] ${context.request.url ?? ''}`);
    }
    return next(context.request);
  },
};

export default useRecommendedStore({
  cache: JSONAPICache,
  handlers: [LoggingHandler],
});

The trade-off versus the getOwner/setOwner pattern above is that context.request.store is only populated for requests issued via store.request(...); a request made directly against a RequestManager won't have it set unless the caller supplies it explicitly, so a handler relying on it should treat it as optional (as LoggingHandler does above).

Type Parameters ​

T ​

T extends Cache

Parameters ​

options ​

StoreSetupOptions<T>

StoreKlass? ​

typeof Store

Returns ​

typeof ConfiguredStore

Released under the MIT License.