Overview
The GeneroService provides methods to create, read, update, and delete book genres in the Biblioteca Virtual system. It handles all HTTP communications with the backend /generos endpoint.
Location: src/app/core/services/genero.ts
Constructor
private http = inject(HttpClient);
Uses Angular’s inject() function to obtain HttpClient instance.
Properties
apiUrl
string
default:"${environment.apiUrl}/generos"
Base URL for genero endpoints, configured from environment settings.
Methods
getAll()
Retrieves all genres from the database.
getAll(): Observable<Genero[]>
Returns: Observable<Genero[]> - Array of all genres
Array of genre objectsGenre name (e.g., “Ciencia Ficción”, “Romance”, “Terror”)
Example:
this.generoService.getAll().subscribe({
next: (generos) => {
console.log(`Found ${generos.length} genres`);
this.genres = generos;
},
error: (error) => {
console.error('Error fetching genres:', error);
}
});
API Endpoint: GET ${apiUrl}
getById()
Retrieves a specific genre by its ID.
getById(id: number): Observable<Genero>
The unique identifier of the genre to retrieve
Returns: Observable<Genero> - Single genre object
Example:
const generoId = 3;
this.generoService.getById(generoId).subscribe({
next: (genero) => {
console.log('Genre details:', genero.nombre);
this.selectedGenre = genero;
},
error: (error) => {
console.error('Genre not found:', error);
}
});
API Endpoint: GET ${apiUrl}/{id}
Use Case: Loading genre data for editing forms
create()
Creates a new genre in the database.
create(genero: Genero): Observable<Genero>
Genre data to createRequired Properties:
nombre (string): Genre name
Optional Properties:
id (number): Should be omitted for new genres (server assigns)
Returns: Observable<Genero> - The created genre with server-assigned ID
Example:
const newGenre: Genero = {
id: 0, // Will be assigned by server
nombre: 'Ciencia Ficción'
};
this.generoService.create(newGenre).subscribe({
next: (createdGenero) => {
console.log('Genre created with ID:', createdGenero.id);
this.router.navigate(['/generos']);
},
error: (error) => {
console.error('Error creating genre:', error);
}
});
API Endpoint: POST ${apiUrl}
update()
Updates an existing genre.
update(id: number, genero: Genero): Observable<Genero>
The ID of the genre to update
Updated genre dataProperties:
id (number): Genre ID (should match path parameter)
nombre (string): Updated genre name
Returns: Observable<Genero> - The updated genre object
Example:
const updatedGenre: Genero = {
id: 3,
nombre: 'Ciencia Ficción Moderna'
};
this.generoService.update(3, updatedGenre).subscribe({
next: (genero) => {
console.log('Genre updated successfully:', genero.nombre);
this.loadGenres();
},
error: (error) => {
console.error('Error updating genre:', error);
}
});
API Endpoint: PUT ${apiUrl}/{id}
delete()
Deletes a genre from the database.
delete(id: number): Observable<any>
The ID of the genre to delete
Returns: Observable<any> - Plain text response from server
Response Type: Text (uses responseType: 'text' to accept string responses from backend)
Example:
const generoId = 3;
if (confirm('¿Está seguro de eliminar este género?')) {
this.generoService.delete(generoId).subscribe({
next: (response) => {
console.log('Delete response:', response);
this.loadGenres(); // Refresh the list
},
error: (error) => {
console.error('Error deleting genre:', error);
// May occur if genre has associated books
}
});
}
API Endpoint: DELETE ${apiUrl}/{id}
Note: Deletion may fail if the genre has associated books. Handle this error appropriately in your UI.
Complete CRUD Example
Example component using all GeneroService methods:
import { Component, OnInit, inject } from '@angular/core';
import { GeneroService } from '../core/services/genero';
import { Genero } from '../core/models/genero';
import { Router } from '@angular/router';
@Component({
selector: 'app-genero-list',
templateUrl: './genero-list.html'
})
export class GeneroListComponent implements OnInit {
generoService = inject(GeneroService);
router = inject(Router);
generos: Genero[] = [];
loading = false;
ngOnInit() {
this.loadGeneros();
}
loadGeneros() {
this.loading = true;
this.generoService.getAll().subscribe({
next: (data) => {
this.generos = data;
this.loading = false;
},
error: (err) => {
console.error('Error loading genres:', err);
this.loading = false;
}
});
}
editGenero(id: number) {
this.router.navigate(['/generos/editar', id]);
}
deleteGenero(id: number, nombre: string) {
if (confirm(`¿Eliminar género "${nombre}"?`)) {
this.generoService.delete(id).subscribe({
next: () => {
this.loadGeneros();
},
error: (err) => {
alert('No se puede eliminar el género. Puede tener libros asociados.');
}
});
}
}
}
Example form component for creating/editing genres:
import { Component, OnInit, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { GeneroService } from '../core/services/genero';
import { Genero } from '../core/models/genero';
@Component({
selector: 'app-genero-form',
templateUrl: './genero-form.html'
})
export class GeneroFormComponent implements OnInit {
generoService = inject(GeneroService);
route = inject(ActivatedRoute);
router = inject(Router);
genero: Genero = { id: 0, nombre: '' };
isEditMode = false;
ngOnInit() {
const id = this.route.snapshot.paramMap.get('id');
if (id) {
this.isEditMode = true;
this.loadGenero(Number(id));
}
}
loadGenero(id: number) {
this.generoService.getById(id).subscribe({
next: (data) => {
this.genero = data;
}
});
}
save() {
if (this.isEditMode) {
this.generoService.update(this.genero.id, this.genero).subscribe({
next: () => this.router.navigate(['/generos']),
error: (err) => console.error('Error updating:', err)
});
} else {
this.generoService.create(this.genero).subscribe({
next: () => this.router.navigate(['/generos']),
error: (err) => console.error('Error creating:', err)
});
}
}
}
GeneroService is commonly used to populate dropdown selectors when creating/editing books:
import { Component, OnInit, inject } from '@angular/core';
import { GeneroService } from '../core/services/genero';
import { LibroService } from '../core/services/libro';
import { Genero } from '../core/models/genero';
@Component({
selector: 'app-libro-form',
templateUrl: './libro-form.html'
})
export class LibroFormComponent implements OnInit {
generoService = inject(GeneroService);
libroService = inject(LibroService);
availableGenres: Genero[] = [];
selectedGenre?: Genero;
ngOnInit() {
// Load all genres for the dropdown
this.generoService.getAll().subscribe({
next: (generos) => {
this.availableGenres = generos;
}
});
}
saveBook() {
const bookData = {
titulo: 'Book Title',
genero: this.selectedGenre,
// ... other fields
};
this.libroService.create(bookData).subscribe({
next: (libro) => console.log('Book created with genre:', libro.genero.nombre)
});
}
}
Data Model
Genero Interface
export interface Genero {
id: number;
nombre: string;
}
Error Handling
Common error scenarios and how to handle them:
this.generoService.create(newGenre).subscribe({
next: (response) => { /* success */ },
error: (error) => {
if (error.status === 400) {
console.error('Invalid genre data');
} else if (error.status === 409) {
console.error('Genre name already exists');
} else if (error.status === 403) {
console.error('Access forbidden: admin privileges required');
} else {
console.error('Unexpected error:', error);
}
}
});
See Also