Llamadas a API basadas en signals
A partir de Angular v19.2, podemos comenzar a olvidarnos de manejar llamadas a API de manera manual gracias a la nueva primitiva de Angular. httpResource
la que nos permite de manera reactiva obtener datos, haciendo un llamado a nuestra API de preferencia cada vez que el valor cambie.
Características principales:
- Reactividad automática:
El recurso generado por httpResource
observa señales y automáticamente vuelve a realizar solicitudes HTTP cada vez que las dependencias reactivas cambian.
- Estado por defecto:
Permite establecer valores predeterminados mediante la propiedad defaultValue
, asegurando una respuesta coherente en situaciones iniciales, estados de carga o errores en las solicitudes.
- Validación y transformación de datos:
La opción parse
facilita la validación y transformación automática de las respuestas HTTP, mejorando la seguridad de tipos y garantizando la integridad de los datos recibidos.
Ventajas frente al enfoque tradicional:
Reducción significativa de código: Elimina la necesidad de gestionar manualmente suscripciones, reduciendo errores como memory leaks.
Actualización automática del estado: Al depender directamente de Signals, los datos se actualizan automáticamente según los cambios en el estado reactivo de la aplicación, eliminando tareas manuales.
Mayor seguridad: Promueve un desarrollo robusto mediante validación automática y estricta gestión del estado en todas las fases del ciclo de vida del dato.
Actualmente, esta API se encuentra en fase experimental, por lo que se recomienda seguir su evolución antes de implementarla en entornos de producción críticos.
Ejemplo de uso e implementación:
Anteriormente debíamos recurrir a RxJS para suscribirnos y desuscribirnos cada que hacíamos una llamada de API, lo cual en ciertas ocasiones contribuía a los famosos memory leaks porque si olvidábamos desuscribirnos.
Para implementarlo, deberemos comenzar creando una interfaz (interface) definiendo la estructura de nuestro personaje con datos como ser el id, el nombre, la imagen, etc., etc.
interface RickCharacter { | |
id: number; | |
name: string; | |
status: string; | |
species: string; | |
gender: string; | |
origin: { name: string; url: string }; | |
location: { name: string; url: string }; | |
image: string; | |
episode: string[]; | |
url: string; | |
created: string; | |
} |
Ahora implementamos httpResource en nuestro componente.
import { Component, signal } from '@angular/core'; | |
import { httpResource } from '@angular/common/http'; | |
import { CommonModule } from '@angular/common'; | |
interface RickCharacter { | |
id: number; | |
name: string; | |
status: string; | |
species: string; | |
gender: string; | |
origin: { name: string; url: string }; | |
location: { name: string; url: string }; | |
image: string; | |
episode: string[]; | |
url: string; | |
created: string; | |
} | |
@Component({ | |
selector: 'app-rick-and-morty', | |
standalone: true, | |
imports: [CommonModule], | |
template: 'character.component.html', | |
}) | |
export class RickAndMortyComponent { | |
private readonly apiUrl = 'https://rickandmortyapi.com/api/character/'; | |
/**Selected Character ID as Signal, default to Rick Sanchez (id 1)**/ | |
characterId = signal('1'); | |
/**Fetch data dynamically when `characterId` changes**/ | |
characterResource = httpResource<RickCharacter>( | |
() => ({ | |
url: `${this.apiUrl}${this.characterId()}`, | |
method: 'GET', | |
}), | |
{ defaultValue: undefined } | |
); | |
// Function to update the selected Character | |
updateCharacter(event: Event) { | |
const target = event.target as HTMLSelectElement; | |
this.characterId.set(target.value); | |
} | |
} |
characterResource es un httpResourceRef que devuelve los datos del personaje desde el API; defaultValue se encarga de que characterResource tenga una estructura definida, incluso antes de que los datos sean cargados.
characterId es un signal que representa el número del personaje que se está mostrando. Cambiar este valor acciona httpResource para obtener la data del personaje seleccionado.
<div class="character-container"> | |
<h2>Rick and Morty Characters</h2> | |
<label for="character">Choose a Character:</label> | |
<select id="character" (change)="updateCharacter($event)"> | |
<option value="1">Rick Sanchez</option> | |
<option value="2">Morty Smith</option> | |
<option value="3">Summer Smith</option> | |
<option value="4">Beth Smith</option> | |
<option value="5">Jerry Smith</option> | |
</select> | |
<!-- Show character details when data is available --> | |
<div *ngIf="characterResource.value() as character" class="character-card"> | |
<h3>{{ character.name }}</h3> | |
<img [src]="character.image" [alt]="character.name" /> | |
<p><strong>Status:</strong> {{ character.status }}</p> | |
<p><strong>Species:</strong> {{ character.species }}</p> | |
<p><strong>Gender:</strong> {{ character.gender }}</p> | |
<p><strong>Origin:</strong> {{ character.origin.name }}</p> | |
</div> | |
</div> |
Pero, ¿qué pasa si queremos usar POST, PUT, DELETE?
Solo debemos cambiar el método (method) y su correspondiente body junto a los params.
usersResource = httpResource<RickCharacter>({
url: '',
method: 'POST',
body: { page: 1 },
params: { per_page: 6 },
});
En el siguiente artículo cubriré aspectos más avanzados como headers
params
,etc. pero por ahora puedes ver todo el código funcional en el siguiente:
Ejemplo:
Top comments (0)