Injects
Angular Injects
Angular inject functions for data fetching with full type safety
The @spoosh/angular package provides Angular inject functions for data fetching with full type safety using Signals.
Installation
npm install @spoosh/core @spoosh/angularSetup
import { Spoosh } from "@spoosh/core";
import { create } from "@spoosh/angular";
import { cachePlugin } from "@spoosh/plugin-cache";
import { invalidationPlugin } from "@spoosh/plugin-invalidation";
import { deduplicationPlugin } from "@spoosh/plugin-deduplication";
const spoosh = new Spoosh<ApiSchema, Error>("/api").use([
cachePlugin({ staleTime: 5000 }),
invalidationPlugin(),
deduplicationPlugin({ read: "in-flight" }),
]);
export const { injectRead, injectWrite, injectPages, injectQueue } =
create(spoosh);Automatic Tag Generation
Spoosh automatically generates a cache tag from the resolved API path.
// api("users").GET() → tag: "users"
// api("users/:id").GET({ params: { id: 1 } }) → tag: "users/1"
// api("posts/:postId/comments").GET({ params: { postId: 5 } }) → tag: "posts/5/comments"Custom Tags
Override the auto-generated tag with custom tags:
// Single custom tag
users = injectRead((api) => api("users").GET(), {
tags: "my-users",
});
// Multiple custom tags
users = injectRead((api) => api("users").GET(), {
tags: ["users", "dashboard"],
});Cache Invalidation
The invalidationPlugin automatically refetches queries after mutations using wildcard pattern matching.
Pattern Matching
| Pattern | Matches |
|---|---|
"posts" | Exact match only |
"posts/*" | All children (posts/1, posts/1/comments) |
["posts", "posts/*"] | posts AND all children (default) |
createPost = injectWrite((api) => api("posts").POST());
// Default behavior — invalidates ["posts", "posts/*"]
await createPost.trigger({ body: { title: "New Post" } });
// Specific patterns
await createPost.trigger({
body: { title: "New Post" },
invalidate: ["posts", "posts/*"],
});
// Disable invalidation
await createPost.trigger({
body: { title: "New Post" },
invalidate: false,
});Manual Invalidation
Target specific patterns to invalidate:
createPost = injectWrite((api) => api("posts").POST());
await createPost.trigger({
body: { title: "New Post" },
invalidate: ["posts", "users/*", "dashboard"],
});Request Deduplication
The deduplicationPlugin prevents duplicate network requests when the same query is called multiple times simultaneously.
Deduplication Modes
| Mode | Description |
|---|---|
"in-flight" | Reuse pending request if same query is in progress (default for reads) |
false | Disable deduplication |
users = injectRead((api) => api("users").GET(), { dedupe: "in-flight" });When multiple components call the same query simultaneously, only one network request is made:
@Component({
selector: "app-header",
template: `<div>{{ user.data()?.name }}</div>`,
})
export class HeaderComponent {
user = injectRead((api) => api("me").GET());
}
@Component({
selector: "app-sidebar",
template: `<nav>{{ user.data()?.email }}</nav>`,
})
export class SidebarComponent {
user = injectRead((api) => api("me").GET());
}Available Injects
- injectRead - Fetch data with automatic caching
- injectWrite - Trigger mutations with loading states
- injectPages - Paginated data fetching
- injectQueue - Concurrent request queues with progress tracking