Sergio Hidalgo
Apasionado por la tecnología. Ninja Developer, FullStack, Adm Servidores, Profesor de Angular, Node, Phaser, Javascript. sergiohidalgocaceres@gmail.com https://www.facebook.com/groups/607163139705114/
Requisiones Http
Http
HttpClient
Está depreciado
HttpClient
Para usar el HttpClient necesitamos importar el módulo "HttpClientModule" desde "@angular/common/http"
<!-- app.module.ts -->
import { HttpClientModule } from "@angular/common/http"
...
@NgModule({
...
imports: [
HttpClientModule
],
...
})El módulo "HttpClientModule" tiene un servicio llamado "HttpClient" que debe ser inyectado antes de ser usado.
import { HttpClient } from "@angular/common/http"
...
constructor(private http: HttpClient) {}
...El servicio "HttpClient" puede ser inyectado en componentes, en directivas, en pipes y en general en cualquier clase.
Lo ideal es que sea inyectado en otro servicio.
El "HttpClient" tiene cuatro métodos (entre otros) que nos permiten conectarnos a un API Rest: GET, POST, PUT y DELETE
...
this.http.get // Para listar registros o consultar por uno.
this.http.post // Para insertar registros
this.http.put // Para modificar registros
this.http.delete // Para eliminar registros
...Los cuatro métodos anteriores tienen parámetros son métodos genéricos, es decir, pueden recibir y devolver datos tipos de datos diferentes.
Método GET
this.http.get<T>(url, opciones)Método POST
this.http.post<T>(url, data, opciones)Método PUT
this.http.put<T>(url, data, opciones)Método DELETE
this.http.delete<T>(url, data, opciones)T: Es el tipo de dato que devolverá el API Rest
URL: Es la dirección del API Rest (endpoint)
DATA: Son los datos que se enviarán al API Rest. El formato puede ser un JSON.
OPCIONES: Aquí podemos incluir cabeceras, indicarle al API Rest el tipo de datos que esperamos recibir, indicar en qué parte de la respuesta del API Rest procesaremos, etc. Las opciones son un objeto JSON.
Environments
Angular define tres ambientes: Development, Production y HMR
Los tres ambientes están definidos por tres archivos ubicados en la carpeta "src/environments".
environment.ts: Es el ambiente de desarrollo, aquí seteamos nuestras "variables de entorno"
environment.prod.ts: Es el ambiente de producción, aquí estarán las "variables de entorno" que usaremos en producción.
environment.hmr.ts: Es el nuevo ambiente llamado HMR, implementado por Webpack y definido por Angular6.
Para usar las "variables de entorno", debemos primero importar el archivo de entorno.
import { environment } from "environments/environment";Luego podemos usarlas a través de la variable exportada "environment".
Cuando estamos en desarrollo, usamos el comando "ng serve".
Angular usa el archivo environment.ts
Cuando compilamos para producción, usamos el comando "ng build --prod".
Angular intercambia el archivo enviroment.ts por el archivo environment.prod.ts
Cuando ejecutamos en modo HMR, usamos el comando "ng serve --hmr".
Angular intercambia el archivo environment.ts por environment.hmr.ts
Aún cuando usemos el modo HMR, la página igual seguirá recargándose.
Para utilizar la potencia del Webpack en modo HMR, hay que adicionar código.
https://webpack.js.org/guides/hot-module-replacement/
Regresando al HttpClient
Inyectemos el HttpClient en un servicio.
...
import { HttpClient } from "@angular/common/http"
...
@Injectable()
export class AutenticacionService {
...
constructor(private http: HttpClient) {}
...
}Definamos la ruta del API Rest en los "environments"
export const environment = {
production: false,
rutaAPIRest: "la ruta del api rest"
};Traigamos la ruta del API Rest
...
import { HttpClient } from "@angular/common/http"
import { environment } from "environments/environment"
...
@Injectable()
export class AutenticacionService {
rutaApiRest: string
...
constructor(private http: HttpClient) {
this.rutaApiRest = environment.rutaAPIRest
}
...
}Los métodos GET, POST, PUT, DELETE devuelven un observable.
Creemos un método listar y un método insertar en el servicio.
...
constructor(private http: HttpClient) {
this.rutaApiRest = environment.rutaAPIRest
}
...
listar(): Observable<IUsuario[]> {
return this.http.get<IUsuario[]>(this.rutaApiRest)
}
insertar(usuario: IUsuario): Observable<IUsuario> {
return this.http.post<IUsuario>(this.rutaApiRest, usuario)
}
...Supongamos que el servicio se llama "UsuarioService" y que lo inyectamos en un componente a través de la propiedad privada "usuarioService".
...
constructor(private usuarioService: UsuarioService) {}
...
obtenerListaUsuarios() {
this.usuarioService.listar()
.subscribe(
(data: IUsuario[]) => this.listaUsuarios = data,
error => console.log(error)
)
}
...Si bien cada componente puede manejar los errores, una mejor forma sería que el servicio mismo los manejara.
Creemos una clase llamada "Errores"
import { HttpErrorResponse } from "@angular/common/http";
import { throwError } from "rxjs";
export class Errores {
manejador(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
console.log("Ocurrió un error", error.error)
} else {
console.log("Estado", error.status)
console.log("Detalle", error.error.mensaje)
}
return throwError("Ocurrió un error")
}
}Usémosla en el servicio. El método "catchError" pertenece a la programación reactiva "rxjs". El método "pipe" crea un "tubo" que procesa etapas.
...
import { Errores } from "./errores"
import { catchError } from 'rxjs/operators';
@Injectable()
export class UsuarioService {
objErrores: Errores = new Errores()
...
listar(): Observable<IUsuario[]> {
return this.http.get<IUsuario[]>(this.rutaApiRest)
.pipe(
catchError(this.objErrores.manejador)
)
}
...
}A veces las fallas en las llamadas a un API Rest son instantáneas y debidas a una falla en la capa de transporte, pero sin embargo por más pequeño que sea el tiempo de interrupción, la llamada se cancela. Esto es más notorio en los móviles.
Una alternativa es reintentar la llamada varias veces sucesivamente a través del método "retry".
import { catchError, retry } from 'rxjs/operators';
...
listar(): Observable<IUsuario[]> {
return this.http.get<IUsuario[]>(this.rutaApiRest)
.pipe(
retry(3),
catchError(this.objErrores.manejador)
)
}
...
Hay veces en las que los API Rest (endpoints) están protegidos y necesitan que se les envíe una autenticación.
Supongamos el caso que requiera una autenticación de tipo token (usaremos "Bearer"). Supongamos que el token está guardado en el localStorage. La autenticación se envía a través de una cabecera.
import { HttpClient, HttpHeaders } from "@angular/common/http";
...
listar(): Observable<IUsuario[]> {
const accessToken: string = localStorage.getItem("accessToken")
const headers: HttpHeaders = new HttpHeaders({
"authorization": `Bearer ${accessToken}`
})
...
}
...
import { HttpClient, HttpHeaders } from "@angular/common/http";
...
listar(): Observable<IUsuario[]> {
const accessToken: string = localStorage.getItem("accessToken")
const headers: HttpHeaders = new HttpHeaders({
"authorization": `Bearer ${accessToken}`
})
return this.http.get<IUsuario[]>(this.rutaApiRest, {headers})
.pipe(
retry(3),
catchError(this.objErrores.manejador)
)
}
...
Se debe enviar la cabecera con la autenticación en cada API Rest que los requiera. Esto puede ser un problema si tenemos muchas llamadas a API Rest.
Los interceptores
Los interceptores capturan cada requisión (request), crean un clon, lo modifican y la reenvían al API Rest de destino.
Request
Servidor
Interceptor
Request (clon)
Agrega la cabecera
con la autenticación
Un interceptor es una clase que implementa la interface "HttpInterceptor"
import { Injectable } from "@angular/core";
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent} from "@angular/common/http";
import { Observable } from "rxjs/Observable";
@Injectable()
export class AppInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const accessToken: string = localStorage.getItem("accessToken")
const requestClone = req.clone({
headers: req.headers.append("authorization", token)
})
return next.handle(requestClone)
}
}El interceptor debe declararse en un módulo.
@NgModule({
...
providers: [
...
{ provide: HTTP_INTERCEPTORS,
useClass: AppInterceptor,
multi: true
}
...
],
bootstrap: [...]
})
export class AppModule { }By Sergio Hidalgo
Aprendamos a consumir API Rest a través del módulo HttpClient. Aprendamos a usar un interceptor.
Apasionado por la tecnología. Ninja Developer, FullStack, Adm Servidores, Profesor de Angular, Node, Phaser, Javascript. sergiohidalgocaceres@gmail.com https://www.facebook.com/groups/607163139705114/