Ofreciendo muchas soluciones fuera de la caja para casos de uso complejos, Angular es uno de los mejores frameworks para desarrollar aplicaciones de una sola página. Otra gran cosa sobre Angular es que es muy opinable sobre la arquitectura.
Esto es especialmente importante para los equipos de desarrollo más grandes, ya que facilita la incorporación de nuevos miembros y la comunicación entre los diferentes equipos de una organización.
La CLI (interfaz de línea de comandos) de Angular es otra herramienta increíble. Nos permite andamiar toda una aplicación Angular con un solo comando y realizar tareas comunes como extender, linting, probar y construir nuestra aplicación.
NestJS, por otro lado, es un framework para desarrollar aplicaciones backend con TypeScript. Está basado en Express JS. Si nunca has oído hablar de NestJS, te recomiendo que eches un vistazo a este artículo:
Esto es lo bueno. Nest está profundamente inspirado en Angular. Ofrece soluciones listas para usar para muchos problemas, viene con los mismos bloques de construcción arquitectónicos y una interfaz de línea de comandos similar.
Esta similitud hace que sea muy fácil para los desarrolladores de Angular implementar características de backend. Puedes aplicar los mismos principios del backend al frontend.
Echemos un vistazo más de cerca aprendiendo un puñado de comandos para construir una aplicación Angular con un backend NestJS.
Lo que vamos a construir
Vamos a construir una pequeña aplicación que muestre jugadores del Real Madrid😉.
La aplicación Angular obtendrá los datos a través de REST desde un backend de Nest y los mostrará.
Para construir esta aplicación, vamos a utilizar la CLI de Nest y la CLI de Angular.
Los bloques de construcción básicos
Como se mencionó en la introducción, Angular y Nest utilizan los mismos conceptos arquitectónicos/bloques de construcción.
Módulos
Los módulos son la parte principal de toda aplicación Nest y Angular. Una aplicación pequeña puede consistir en un solo módulo, mientras que una aplicación más grande suele contener múltiples módulos.
Servicios
Los servicios son una gran manera de encapsular la lógica en una clase dedicada. Esto aumenta la encapsulación y la capacidad de prueba.
Componentes / Controlador
En Angular, hablamos de componentes, mientras que en NestJS, utilizamos Controladores. En el frontend, un componente representa un pequeño bloque en la UI. Un componente contiene una clase TypeScript, un archivo HTML, un archivo de estilos y un archivo .spec para pruebas.
En el backend, un controlador contiene métodos que entregan respuestas sobre REST.
Ambos CLIs ofrecen un gran soporte para generar esas características fuera de la caja.
Construyendo el backend
Empecemos por construir nuestra aplicación backend. Para construir una aplicación NestJS, usamos la CLI Nest que podemos instalar globalmente usando el siguiente comando.
npm i -g @nestjs/cli
Una vez instalado, podemos utilizar la CLI para crear un nuevo proyecto NestJS. Primero vamos a crear una carpeta para nuestro proyecto y cambiar en él.
mdkir playersapp
cd playersapp
Ahora, es el momento de crear la aplicación
nest new playersapp-backend
Una vez completado el asistente de configuración, terminamos con una aplicación NestJS. Una vez creada, podemos utilizar el script de inicio (npm start) para poner en marcha nuestro servidor. Actualmente, nuestro servidor tiene un controlador que devuelve Hello World en el puerto 3000. Ahora estamos listos para ampliar nuestra aplicación.
Añadir players endpoint
Como se mencionó anteriormente, Nest JS está profundamente inspirado en Angular. Por lo tanto, utiliza los mismos bloques de construcción. Uno de los bloques de construcción para las nuevas características es un módulo.
Un módulo es una pieza importante de la arquitectura limpia porque contiene múltiples componentes que pertenecen juntos.
nest g module players
Generamos un player's module que contendrá el controlador REST y el player's service.
La ejecución de este comando añade automáticamente el módulo recién creado imports array
en el app.module.ts
Un módulo en sí mismo es bastante inútil; lo que necesitamos a continuación es un servicio que entregue a los jugadores.
nest g service players
Este comando generará players.service.ts
, players.service.spec.ts
y lo registrará en players.module.ts
.
Hasta ahora, el players.service.ts
es bastante aburrido. Es una simple clase TypeScript con una anotación.
El trabajo de este servicio es entregar una serie de jugadores. Una aplicación del mundo real como un servicio suele obtener los jugadores de una base de datos. Para nuestro pequeño ejemplo, es suficiente con añadirlos como un campo de clase pública.
import { injectable } from '@nestjs/common';
@injectable ()
export class playersService {
public players = [
{
name: 'thibaut Curtois',
imgURL: https://....
info: Texto
},
{
name: 'Sergio Ramos',
imgURL: https://....
info: Texto
},
//....
];
}
Bien, hemos creado un módulo y un servicio que expone una serie de jugadores. Pero hasta ahora, los jugadores todavía no son accesibles a través de REST. Necesitamos un controlador.
nest g controller players
Este comando añade un players.controller.ts
, un players.controller.spec.ts
y lo añade al players.modle.ts
.
De nuevo, players.controller.ts
es una clase TypeScript simple con la anotación @Controller
. Para entregar los jugadores, podemos usar la inyección de dependencia de Nest para obtener el PlayersService
y luego usarlo para acceder a los jugadores en un método con la anotación @Get
La anotación @Get
indica a Nest que este método debe ser llamado si hacemos una petición GET
a este controlador.
import {controller, get} from '@nestjs/common';
import {playersService} from './players.service';
@controller ('players')
export class playersController {
constructor(private PlayersService: PlayerServices) {
}
@get()
public players (): any {
return this.PlayersService.players;
}
}
Eso es todo para nuestro backend. Ahora podemos realizar una petición GET a través de la línea de comandos o Postman a localhost:3000/players
Podemos abrir esta URL en un navegador para ver el array de jugadores devuelto por nuestro controlador.
¡Épico! Implementamos una API REST con 4 simples comandos:
nest new players-backend
nest g module players
nest g service players
nest g component players
Nuestro servidor está listo. Pero ya sabemos que nuestro frontend en desarrollo local será servido en un puerto diferente al del servidor. Para permitir peticiones desde un puerto diferente, necesitamos establecer las cabeceras CORS (cross-origin resource sharing) correctas. Nest JS nos permite llamar al método enableCors
de nuestra app dentro del main.ts
.
const app = await NestFactory.create (AppModule);
app.enableCors ();
await app.listen(3000);
En una aplicación del mundo real no querrás permitir que todos los recursos accedan a tu backend. Por lo tanto, tu configuración CORS debe ser más sofisticada. Puedes encontrar más información en los documentos oficiales de Nest
Construyendo la aplicación Angular
Pasemos al frontend e implementemos nuestra aplicación Angular para mostrar la lista de jugadores. Al igual que Nest, también utilizaremos una interfaz de línea de comandos llamada Angular CLI para armar nuestra aplicación.
npm i -g @angular/cli
Una vez instalado, podemos generar nuestro frontend junto al backend.
ng new players-app
Después de completar el asistente de configuración, podemos utilizar npm start
o ng serve
para poner en marcha nuestra aplicación Angular en localhost:4200
Al igual que el backend, crearemos un módulo de jugadores para agrupar lógicamente los servicios y componentes.
ng g module players --module=app
A diferencia del comando Nest, el comando ng g module player
genera un players.module.ts
pero no actualiza el app.module.ts
Es necesario especificar el módulo a actualizar con la bandera --module
.
De nuevo, un módulo por sí solo no hace nada. Necesitamos tener un servicio y un componente. Empecemos por generar un servicio.
ng g service players
Este comando crea un players.service.ts
y un players.service.spec.ts
Usemos el HTTPClient
de Angular para solicitar los jugadores desde nuestro backend.
import { Injectable } from '@angular/core';
import {HtttpClient} from '@angular/common/http';
import {observable} from 'rxjs';
@Injectable ( {
providedIN: 'root'
})
export class PlayersService {
constructor(private httpClient) { }
public getPlayers(): observable<player []> {
return this.http.get('http://localhost:3000/players');
}
}
Nuestro PlayersService
proporciona un método público getPlayers
que obtiene un array de jugadores. A continuación, necesitamos un componente que llame a este método.
ng g component players
Hemos creado con éxito un componente. La CLI nos crea automáticamente el archivo TypeScript, un archivo .spec
para pruebas y un archivo HTML y de estilos según la configuración de estilos que hayas elegido durante el asistente de configuración.
Ahora podemos inyectar el PlayersService
en nuestro componente y llamarlo en el hook del ciclo de vida ngOnInit
para asignar los jugadores recuperados a un campo players$.
import { Componet, OnInit } from '@angular/core';
import {observable} from './players.service';
@component ({
Selector: 'app-players',
templateURL: './players.component.html',
StyleUrls: ['./players.component.css']
})
export class PlayersComponent implements OnInit {
players$: observable<any>;
constructor (private playersService: PlayersService) {}
ngOnInit () {
this.players$ = this.playersService.getPlayers ();
}
}
Para mostrar nuestros reproductores$
utilizamos Angulars async
pipe en combinación con la directiva ngFor
.
<div class="row">
<div class= "players" *ngFor="let player of players$ | async">
<img [src]="player.imgURL" class="card-img-top" alt = "...">
<div class="card-body">
<h3 class="card-title">{{ player.name }}</h3>
<p class="card-text"> {{ player. info }} </p>
</div>
</div>
</div>
Lo último que nos queda es implementar un componente navbar y colocar algunos estilos para la lista de nuestro reproductor.
Si ahora ejecutamos ng serve
nos encontramos con la siguiente página.
¡Épico! Implementamos nuestro frontend con 4 comandos CLI y un par de líneas de código extra.
ng new players-frontend
ng g module players --module=app
ng g service players
ng g component players
Apréndelo una vez - aplícalo en el frontend y en el backend
A lo largo de este artículo, probablemente hayas notado la similitud entre los comandos y los bloques de construcción de la arquitectura que hemos utilizado al implementar la aplicación del frontend y el backend.
Te invito a que puedas continuar leyendo más artículos como esté en el blog.