An open API service indexing awesome lists of open source software.

https://github.com/leolanese/angular19-api-observable-signal

Angular (19+) Request API based on Observable, Signal (state management, effect, httpResource, input-pattern, model)
https://github.com/leolanese/angular19-api-observable-signal

angular httpresource input input-signal observable resful-api rxjs signals

Last synced: about 1 year ago
JSON representation

Angular (19+) Request API based on Observable, Signal (state management, effect, httpResource, input-pattern, model)

Awesome Lists containing this project

README

          

# Angular (19.2+) Observable + Signals for handling API requests

πŸ”΄
🟑
🟒
🏁

## ⏺ Goals AC's

### ⏺ Test legacy Angular Vs new modern Angular practices

Test API based on Observable, Signal (state management, effect, httpResource, input-pattern, model)

### ⏺ Test simple/direct Api Request using a few API services:

https://jsonplaceholder.typicode.com/posts

https://swapi.dev/api/vehicles

### ⏺ Test complex/nested API Requests

1. Get all country names and display on the page:
https://restcountries.com/v3.1/independent?fields=name

2. Select a country and Show the flag:
https://restcountries.com/v3.1/name/Grenada?fields=name,flags

3. Search countries by language:
https://restcountries.com/v3.1/lang/spanish?fields=name

---

## πŸ”Έ Demo

![modern-angular](./src/assets/signals-modern-angular.png)

---

## πŸ”Έ Example Solution Arquitecture

```js
src/
└── app/
β”œβ”€β”€ SoC/
└── input/output // Separation of Concern using Parent and Child, @Input()/@Output()
└── input/output // Separation of Concern using Parent and Child, input signal/@Output()
β”œβ”€β”€ orphan-observable/ // single Component, managing API request using Observables
β”œβ”€β”€ orphan-signal/ // single Component, managing API request using Signals
β”œβ”€β”€ orphan-signal-simple/ // single Component, managing API request using Signal
β”œβ”€β”€ orphan-signal-nested/ // single Component, managing complex API request using Signal
β”œβ”€β”€ orphan-signal-httpresource/ // simple Component, managing API request using Signals with httpResouce asynchronous data fetching
β”œβ”€β”€ orphan-signal--httpresource-reactiveForm/ // Shows how the new signals approach replaces the traditional RxJS pattern
β”œβ”€β”€ orphan-signal-httpresource-signal/ // 100% fully signal-based. Using direct signal binding with [value] and (input). Simple event handler to update the signal
β”œβ”€β”€ orphan-signal-input-pattern/ // full signal-based approach: 1-way binding
β”œβ”€β”€ orphan-signal-model/ // full signal-based approach: 2-way binding
|
β”œβ”€β”€ app.component.ts
β”œβ”€β”€ auth.interceptor.ts
└── http.interceptor.ts
```

## πŸ”Έ Technical mentions

🟑 Green solutions are 100% fully reactive signal-based which are Angular recommendations:

πŸ”΅ Reactive state management

- `All state is managed through signals in the service`

πŸ”΅ Data Management:

- `No local component state variables` that aren't signals
- `No RxJS Observables or Subjects`

πŸ”΅ HTTP Handling:

- `Signal with httpresource`, for automatic data fetching

πŸ”΅ Template Binding:

- Replaces `NgModel` is part of the older Forms API, while signals represent Angular's future
- `All template expressions use signals` (vehicleService.searchTerm(), vehicleService.isLoading(), etc.)
- Uses `modern Angular control flow` (@if, @else, @for)

πŸ”΅ Data Flow:

### `Unidirectional Data Flow`:

```js
Signal β†’ View ([property] binding) = [value]="searchSignal()
View β†’ Signal (event() handler) = (input)="signal.set()"
```

- Use `signal-input-pattern`: `[value] + (input) pattern`:
`It's simply a combination of 1-way binding (Property [value]="searchSignal()" + event binding (input)="signal.set()")`

- `Direct Signal Control` (when is read = binding, when is updated = event handler)

### `Bidirectional Data Flow` (model() implement 2-way binding simplify two-way binding boilerplate

πŸ”΅ Event Handling:

- Input events directly update signals (this.vehicleService.searchTerm.set(value))
- No intermediate transformations using RxJS operators

πŸ”΅ Service Implementation:

- Uses httpResource for HTTP requests (instead HttpClient)
This provides:
- Automatically fetches data when the component initializes.
- Handles loading, success, and error states without extra code.
- Provides a .value() method to access the latest data.
- Supports reloading with .reload().
- Stays within the signals paradigm and use signals' effect() to automatically handle cleanup (instead OnInit/OnDestroy + No need for manual subscription management)

🟑 Other technical mentions

πŸ”΅ `SoC`
This example demonstrates the separation of concerns between the:
`service (responsible for fetching data)`,
`smart component (responsible for handling business logic and passing data to the dummy component)`, `dummy component (responsible for rendering the UI)`

πŸ”΅ `Modern StandAlone Components`:
I directly bootstrap the component itself, not its module. This is because standalone components have their own injectors and don't rely on a root module for dependency injection. Promotes code maintainability, reusability, and smaller application size.

πŸ”΅ Implemented `TSP mechanism`:
I'm using `Tree Shakeable Providers` in `Services` by using the `providedIn` attribute, this will provide the benefits of both `tree shaking performance` and `dependency injection`,
meaning that our services will not be included in the final bundle unless they are being used by other services or components. As a result we reduce the bundle size by removing unused code from the bundle.

πŸ”΅ `RxJS`

- `takeUntilDestroyed(this.destroyRef)` to automatically unsubscribe when the component is destroyed, simplifying the cleanup process even further
- `shareReplay(1)` because multiple components might subscribe to the same observable

πŸ”΅ `Dependency Injection Pattern`:
I'm using Modern `Dependency Injection functions`, instead traditional `constructor-based dependency injection`as result I will have a more Modular, Less Complex

πŸ”΅ Implement Caching:
-- `Cache API Service Calls`
Caches identical HTTP requests within a single component:
I'm using `shareReplay()` to improve efficiency, ensuring that all subscribers receive the most recent data without triggering multiple HTTP requests.

πŸ”΅ `DestroyRef & takeUntilDestroyed()`: Angular 16+
I'm using provides a more declarative and efficient way to handle automatic cleanup tasks when a component or service is destroyed: `takeUntilDestroyed(this.destroyRef)` to automatically unsubscribe when the component is destroyed, simplifying the cleanup process even further

πŸ”΅ `Function-based Interceptor` (optional):
It also showcases the usage of an interceptor to log HTTP requests and responses. While not necessary for this example, it can be useful for debugging and monitoring purposes (WIP)

---

### :100: Thanks!

#### Now, don't be an stranger. Let's stay in touch β€Ό


leolanese’s GitHub image

##### :radio_button: gitroll: LeoLanese

##### :radio_button: Linkedin: LeoLanese

##### :radio_button: Twitter: @LeoLanese

##### :radio_button: Blog: dev.to/leolanese

##### :radio_button: Questions / Suggestions / Recommendations: developer@leolanese.com