====== 07 - Consumo de APIs REST ======
Desde el navegador o Node, la función ''fetch'' envía peticiones **HTTP** a una API REST y devuelve una promesa con la respuesta. Es el mecanismo con el que el front de TypeScript consume las APIs creadas en Programación.
===== 1. fetch y async/await =====
async function getBook(id: number): Promise {
const response = await fetch(`/api/books/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
* ''await'' pausa hasta que llega la respuesta sin bloquear el hilo.
* ''response.ok'' es ''true'' con códigos 2xx.
* ''response.json()'' lee y parsea el cuerpo como JSON.
Una función ''async'' devuelve una **Promise**; el error se captura con ''try/catch'':
try {
const book = await getBook(42);
render(book);
} catch (error) {
showErrorMessage("No se pudo cargar el libro");
}
===== 2. GET y POST =====
// GET: petición por defecto
const books = await fetch("/api/books?genre=novel").then(r => r.json());
// POST: envía un cuerpo JSON
async function createBook(book: CreateBookRequest): Promise {
const response = await fetch("/api/books", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(book),
});
if (response.status !== 201) {
throw new Error(`HTTP ${response.status}`);
}
}
^ Método ^ Uso ^
| ''GET'' | Consultar; sin cuerpo |
| ''POST'' | Crear; cuerpo JSON |
| ''PUT'' | Reemplazar un recurso |
| ''DELETE'' | Eliminar |
===== 3. Cabeceras =====
headers: {
"Content-Type": "application/json", // formato del cuerpo enviado
"Accept": "application/json", // formato esperado en la respuesta
"Authorization": `Bearer ${token}` // autenticación
}
===== 4. Autenticación con tokens =====
La API de login de Programación entrega un **token de acceso**; el cliente lo guarda y lo envía en cada petición protegida:
async function login(email: string, password: string): Promise {
const response = await fetch("/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});
if (!response.ok) {
throw new Error("Invalid credentials");
}
return response.json(); // { accessToken, refreshToken }
}
async function getProfile(token: string): Promise {
const response = await fetch("/auth/me", {
headers: { "Authorization": `Bearer ${token}` },
});
if (response.status === 401) {
// token caducado o inválido: renovar o pedir login
}
return response.json();
}
^ Respuesta ^ Interpretación ^
| ''200''/''201'' | Operación correcta |
| ''400'' | Petición mal formada |
| ''401'' | Token ausente, caducado o inválido |
| ''403'' | Autenticado pero sin permisos |
| ''404'' | Recurso inexistente |
===== 5. Errores =====
El cuerpo de error es también JSON, con un formato acordado por la API:
{ "code": "USER_ALREADY_EXISTS", "message": "No se puede crear el usuario" }
Guarda el token en memoria o en ''sessionStorage'', nunca lo imprimas en logs. Si la respuesta es ''401'', usa el refresh token para renovar el par y repite la petición.