Skip to main content

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
Genero[]
array
Array of genre objects
id
number
Unique genre identifier
nombre
string
Genre 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>
id
number
required
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>
genero
Genero
required
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>
id
number
required
The ID of the genre to update
genero
Genero
required
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>
id
number
required
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.');
        }
      });
    }
  }
}

Form Example

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)
      });
    }
  }
}

Usage in Forms

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

Build docs developers (and LLMs) love