Inicio/Angular 22/Angular 22: el catálogo de repuestos contra Spring Boot
Cargando video...

Angular 22: el catálogo de repuestos contra Spring Boot

¿Duda de esta lección?Te respondemos en #front-end

Angular 22: el catálogo de repuestos contra Spring Boot

J

José Díaz

Fundador de JoeDayz y JefToken | Arquitecto Senior

Angular 22

Generás el API con Spring Boot 4.1.2 en el 8080 y el front con Angular 22 en el 4200. Un signal recibe el JSON y la tabla lo pinta con @for.

Sumario

El entorno

La clase usa Java 25 (Temurin), Node v26.13.0 y npm 11.20.0. El repo es joedayz/pevisa-spring-angular, con dos carpetas: backend y frontend.

java -version
node -v
npm -v
npm install -g @angular/cli

El API en el 8080

En start.spring.io el proyecto queda así:

CampoValor
BuildMaven
LenguajeJava
Spring Boot4.1.2
Grouppe.com.pevisaautoparts
Artifactbackend
Java25

Spring Boot trae el servidor embebido. No hace falta desplegar un EAR en Tomcat o Jetty a mano.

El catálogo vive en GET /api/repuestos. El controlador delega en el servicio:

@RestController
@RequestMapping("/api/repuestos")
public class RepuestoController {
    private final RepuestoService repuestoService;

    public RepuestoController(RepuestoService repuestoService) {
        this.repuestoService = repuestoService;
    }

    @GetMapping
    public List<Repuesto> listar() {
        return repuestoService.listar();
    }
}

Cada repuesto tiene id, codigo, nombre, marca, categoria, stock y precio. Lo levantás con el wrapper de Maven:

./mvnw spring-boot:run
curl http://localhost:8080/api/repuestos | jq

El JSON trae 8 ítems. El primero es FLT-001 (filtro de aceite, Mann). Más abajo aparecen ELE-017 (batería Bosch) y ACE-003 (aceite Castrol 5W-30).

El test no llama al servidor: usa MockMvc.

mockMvc.perform(get("/api/repuestos"))
    .andExpect(status().isOk())
    .andExpect(jsonPath("$[0].codigo").value("FLT-001"))
    .andExpect(jsonPath("$.length()").value(8));

Un id que no existe responde 404:

mockMvc.perform(get("/api/repuestos/999"))
    .andExpect(status().isNotFound());

El front con Angular 22

ng new frontend pregunta el sistema de estilos: CSS, Tailwind, Sass o Less. El proyecto de la clase usa CSS. En package.json quedan @angular/core y el resto de paquetes en ^22.2.0, y @angular/cli en ^22.2.5. El package manager fijado es npm@11.20.0.

ng serve

El CLI deja la app en http://localhost:4200. IntelliJ muestra el estado Angular CLI Server.

El componente raíz es standalone, selector app-root. El estado no es un array suelto: es un signal.

protected readonly repuestos = signal<Repuesto[]>([]);
protected readonly cargando = signal(true);
protected readonly error = signal<string | null>(null);

El servicio se inyecta con inject y pide el API con HttpClient:

private readonly http = inject(HttpClient);
private readonly apiUrl = 'http://localhost:8080/api/repuestos';

listar(): Observable<Repuesto[]> {
  return this.http.get<Repuesto[]>(this.apiUrl);
}

El constructor se suscribe y escribe los signals. Si la llamada falla, el mensaje es Error al cargar los repuestos y cargando pasa a false.

La tabla

La página se titula Catálogo de repuestos y muestra 8 repuestos en catálogo. Las columnas son Repuesto, Marca, Categoría, Stock y Precio. El cuerpo no usa *ngFor: usa @for y trackea por id.

@for (repuesto of repuestos(); track repuesto.id) {
  <tr>
    <td class="codigo">{{ repuesto.codigo }}</td>
    <td>{{ repuesto.nombre }}</td>
    <td>{{ repuesto.marca }}</td>
    <td>{{ repuesto.categoria }}</td>
  </tr>
}

@for exige declarar NgForOf en imports del componente. Para el precio se suma CurrencyPipe al mismo arreglo.

El 4200 no es el 8080

El navegador está en el 4200 y el API en el 8080. Sin CORS el HttpClient no lee la respuesta. WebConfig abre solo el origen del front y solo GET:

registry.addMapping("/**")
    .allowedOrigins("http://localhost:4200")
    .allowedMethods("GET");

En DevTools, la petición repuestos vuelve con los 8 ítems y la tabla los pinta.

Un signal se llama

Si en la plantilla escribís {{ error }}, el compilador avisa que error es una función y hay que invocarla. El diagnóstico es NG8109 y la línea es la del estado de error:

<p class="estado error">{{ error() }}</p>

La referencia de ese aviso está en https://v22.angular.dev/extended-diagnostics/NG8109.

El front queda en el repo con el commit listado de repuestos.

¿Duda de esta lección?Te respondemos en #front-end

Contenido

Completa el curso y obtén tu certificado

1 actividades restantes