Signal-native HTTP client for Angular. Wraps the native Fetch API and returns Angular signals directly — no toSignal(), no RxJS required.
Requires Angular 17+.
npm install @assebc/ng-signal-http1. Register the provider
// app.config.ts
import { provideSignalHttp } from '@assebc/ng-signal-http';
export const appConfig: ApplicationConfig = {
providers: [
provideSignalHttp({ baseUrl: 'https://api.example.com' })
]
};2. Fetch data
import { querySignal } from '@assebc/ng-signal-http';
export class UsersComponent {
users = querySignal<User[]>(() => '/users');
// users.data(), users.loading(), users.error() are all ready
}3. Mutate data
import { mutationSignal } from '@assebc/ng-signal-http';
export class CreateUserComponent {
createUser = mutationSignal<CreateUserDto, User>(
(input) => ({ url: '/users', method: 'POST', body: input })
);
onSubmit(dto: CreateUserDto) {
this.createUser.mutate(dto);
}
}HttpClient |
@assebc/ng-signal-http |
|
|---|---|---|
| Return type | Observable<T> |
Signal<T> |
| Loading state | Manual | Built-in |
| Error state | Manual | Built-in |
| Auto-refetch on deps | Manual effect | Automatic |
| RxJS required | Yes | No |
| Request cancellation | Manual | Automatic |
| Retry | Manual | Built-in |
// Before
export class UsersComponent {
private http = inject(HttpClient);
users = toSignal(this.http.get<User[]>('/api/users'), { initialValue: [] });
// loading/error state: manual
// refetch: manual effect
}
// After
export class UsersComponent {
users = querySignal<User[]>(() => '/api/users');
// users.data(), users.loading(), users.error(), users.refetch() — built-in
}Register once in app.config.ts:
provideSignalHttp({
baseUrl: 'https://api.example.com',
timeout: 30_000,
headers: { 'X-API-Version': '2' },
interceptors: [authInterceptor]
})For GET requests. Re-runs automatically when signal dependencies inside urlFactory change.
const result = querySignal<User[]>(() => `/users?page=${page()}`);
result.data() // T | null
result.loading() // boolean
result.error() // Error | null
result.status() // 'idle' | 'loading' | 'success' | 'error'
result.refetch() // manually re-run
result.reset() // clear stateOptions: initialValue, lazy, retry, onSuccess, onError.
For POST / PUT / PATCH / DELETE. Never executes automatically — user-triggered only.
const mutation = mutationSignal<CreateUserDto, User>(
(input) => ({ url: '/users', method: 'POST', body: input })
);
mutation.isPending() // boolean
mutation.data() // TOutput | null
mutation.error() // Error | null
mutation.mutate(input)
mutation.reset()Options: onSuccess, onError, onSettled.
Injectable service for imperative calls in services or guards:
export class UserService {
private http = inject(SignalHttpClient);
getUser(id: number) {
return this.http.get<User>(`/users/${id}`);
}
}All three hooks (request, response, error) support async functions and run in registration order:
const authInterceptor: HttpInterceptor = {
request: async (config) => ({
...config,
headers: { ...config.headers, Authorization: `Bearer ${getToken()}` }
})
};
provideSignalHttp({ interceptors: [authInterceptor] })Signal dependencies inside urlFactory are tracked automatically. When they change, the query re-runs and the previous in-flight request is cancelled:
export class UserDetailComponent {
userId = input.required<number>();
user = querySignal<User>(() => `/users/${this.userId()}`);
// re-fetches whenever userId changes, previous request cancelled
}querySignal(() => '/users', {
retry: { count: 3, delay: (attempt) => 1000 * 2 ** attempt }
})AbortError is never retried. Retry logic applies to both queries and mutations.
- Native Fetch wrapper — no
@angular/common/httpdependency - Signal-native queries with auto-refetch on reactive dependencies
- Signal-native mutations (POST / PUT / PATCH / DELETE)
- Request / response / error interceptors (async, run in order)
- Automatic request cancellation via
AbortControlleron destroy and dep change - Retry with exponential backoff, configurable per-request
- Full TypeScript inference — no explicit generic annotations needed at call sites
- Zero runtime dependencies beyond
@angular/core
v0.2.0 In-memory cache with TTL · stale-while-revalidate · optimistic updates · request deduplication · SSR skip-fetch · refetch on focus / reconnect
v1.0.0 Persistent cache (IndexedDB) · WebSocket signal integration · GraphQL adapter · plugin system
/
├── projects/signal-http/ ← library source
├── projects/demo/ ← Angular SSR demo app
└── projects/demo-e2e/ ← Cypress E2E tests
npm install # install deps
npm start # demo app → http://localhost:4200
npm test # unit tests
npm run build # build the library
npm run lint # lint
npm run start:demo-e2e # Cypress E2EReleases are triggered by pushing a version tag — CI publishes to both npm and GitHub Packages:
git tag v1.0.0 && git push origin v1.0.0MIT