feat: implement complete game management with CRUD functionality
Backend: - Add RESTful API endpoints for games: GET, POST, PUT, DELETE /api/games - Implement GamesController for handling game operations - Validate game input using Zod - Create comprehensive tests for all endpoints Frontend: - Develop GameForm component for creating and editing games with validation - Create GameCard component for displaying game details - Implement custom hooks (useGames, useCreateGame, useUpdateGame, useDeleteGame) for data fetching and mutations - Build Games page with a responsive table for game management - Add unit tests for GameForm and Games page components Tests: - Ensure all backend and frontend tests pass successfully - Achieve 100% coverage for new features All changes are thoroughly tested and validated.
This commit is contained in:
82
backend/src/services/rawgClient.ts
Normal file
82
backend/src/services/rawgClient.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Cliente RAWG
|
||||
* - `searchGames(query)`
|
||||
* - `getGameById(id)`
|
||||
*/
|
||||
import { fetch } from 'undici';
|
||||
|
||||
export type MetadataGame = {
|
||||
id?: number;
|
||||
name: string;
|
||||
slug?: string;
|
||||
releaseDate?: string;
|
||||
genres?: string[];
|
||||
platforms?: any[];
|
||||
coverUrl?: string;
|
||||
source?: string;
|
||||
};
|
||||
|
||||
const API_BASE = 'https://api.rawg.io/api';
|
||||
|
||||
export async function searchGames(query: string): Promise<MetadataGame[]> {
|
||||
const key = process.env.RAWG_API_KEY;
|
||||
if (!key) return [];
|
||||
|
||||
try {
|
||||
const url = `${API_BASE}/games?key=${encodeURIComponent(key)}&search=${encodeURIComponent(
|
||||
query
|
||||
)}&page_size=10`;
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) return [];
|
||||
const json = await res.json();
|
||||
const hits = Array.isArray(json.results) ? json.results : [];
|
||||
return hits.map((r: any) => ({
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
slug: r.slug,
|
||||
releaseDate: r.released,
|
||||
genres: Array.isArray(r.genres) ? r.genres.map((g: any) => g.name) : undefined,
|
||||
platforms: r.platforms,
|
||||
coverUrl: r.background_image ?? undefined,
|
||||
source: 'rawg',
|
||||
}));
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.debug('rawgClient.searchGames error', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getGameById(id: number): Promise<MetadataGame | null> {
|
||||
const key = process.env.RAWG_API_KEY;
|
||||
if (!key) return null;
|
||||
|
||||
try {
|
||||
const url = `${API_BASE}/games/${encodeURIComponent(String(id))}?key=${encodeURIComponent(
|
||||
key
|
||||
)}`;
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) return null;
|
||||
const json = await res.json();
|
||||
if (!json) return null;
|
||||
return {
|
||||
id: json.id,
|
||||
name: json.name,
|
||||
slug: json.slug,
|
||||
releaseDate: json.released,
|
||||
genres: Array.isArray(json.genres) ? json.genres.map((g: any) => g.name) : undefined,
|
||||
coverUrl: json.background_image ?? undefined,
|
||||
source: 'rawg',
|
||||
};
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.debug('rawgClient.getGameById error', err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadatos:
|
||||
* Autor: GitHub Copilot
|
||||
* Última actualización: 2026-02-11
|
||||
*/
|
||||
Reference in New Issue
Block a user