Ejemplos de Uso de la API
Este documento proporciona ejemplos prácticos de escenarios comunes de uso de la API utilizando diversas herramientas como cURL, JavaScript y Go.
Flujo de Autenticación
1. Registrar un Nuevo Usuario
Ejemplo con cURL:
curl -X POST http://localhost:3000/api/v1/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "password": "contraseñasegura123", "first_name": "Juan", "last_name": "Pérez" }'Ejemplo con JavaScript (Fetch API):
fetch('http://localhost:3000/api/v1/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ password: 'contraseñasegura123', first_name: 'Juan', last_name: 'Pérez' }),}).then(response => response.json()).then(data => console.log(data)).catch(error => console.error('Error:', error));Ejemplo con Go:
package main
import ( "bytes" "encoding/json" "fmt" "net/http")
func main() { // Crear cuerpo de la solicitud requestBody, err := json.Marshal(map[string]string{ "password": "contraseñasegura123", "first_name": "Juan", "last_name": "Pérez", }) if err != nil { fmt.Println("Error al crear el cuerpo de la solicitud:", err) return }
// Realizar la solicitud resp, err := http.Post( "http://localhost:3000/api/v1/auth/register", "application/json", bytes.NewBuffer(requestBody), ) if err != nil { fmt.Println("Error al realizar la solicitud:", err) return } defer resp.Body.Close()
// Analizar la respuesta var result map[string]interface{} json.NewDecoder(resp.Body).Decode(&result) fmt.Println("Respuesta:", result)}2. Verificar Email
Después del registro, el usuario recibirá un token de verificación. Utilízalo para verificar su email:
Ejemplo con cURL:
curl -X POST http://localhost:3000/api/v1/auth/verify-email \ -H "Content-Type: application/json" \ -d '{ "token": "token-de-verificacion-recibido-via-email" }'3. Iniciar Sesión
Ejemplo con cURL:
curl -X POST http://localhost:3000/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "password": "contraseñasegura123" }'Respuesta:
{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "expires_in": 900}Ejemplo con JavaScript (Fetch API):
fetch('http://localhost:3000/api/v1/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ password: 'contraseñasegura123' }),}).then(response => response.json()).then(data => { // Almacenar tokens en localStorage o de forma segura en memoria localStorage.setItem('access_token', data.access_token); localStorage.setItem('refresh_token', data.refresh_token); console.log('Autenticación exitosa:', data);}).catch(error => console.error('Error:', error));Ejemplo con Go:
package main
import ( "bytes" "encoding/json" "fmt" "net/http")
func main() { // Crear cuerpo de la solicitud requestBody, err := json.Marshal(map[string]string{ "password": "contraseñasegura123", }) if err != nil { fmt.Println("Error al crear el cuerpo de la solicitud:", err) return }
// Realizar la solicitud resp, err := http.Post( "http://localhost:3000/api/v1/auth/login", "application/json", bytes.NewBuffer(requestBody), ) if err != nil { fmt.Println("Error al realizar la solicitud:", err) return } defer resp.Body.Close()
// Analizar la respuesta var result map[string]interface{} json.NewDecoder(resp.Body).Decode(&result) fmt.Println("Token de Acceso:", result["access_token"]) fmt.Println("Token de Refresco:", result["refresh_token"])}4. Renovar Token
Cuando el token de acceso expire, utiliza el token de refresco para obtener un nuevo par:
Ejemplo con cURL:
curl -X POST http://localhost:3000/api/v1/auth/refresh \ -H "Content-Type: application/json" \ -d '{ "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }'Ejemplo con JavaScript:
fetch('http://localhost:3000/api/v1/auth/refresh', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ refresh_token: localStorage.getItem('refresh_token') }),}).then(response => response.json()).then(data => { // Actualizar tokens en almacenamiento localStorage.setItem('access_token', data.access_token); localStorage.setItem('refresh_token', data.refresh_token); console.log('Tokens renovados exitosamente');}).catch(error => console.error('Error al renovar tokens:', error));5. Cerrar Sesión
Ejemplo con cURL:
curl -X POST http://localhost:3000/api/v1/auth/logout \ -H "Content-Type: application/json" \ -d '{ "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }'Ejemplo con JavaScript:
fetch('http://localhost:3000/api/v1/auth/logout', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ refresh_token: localStorage.getItem('refresh_token') }),}).then(response => { if (response.ok) { // Eliminar tokens del almacenamiento localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); console.log('Sesión cerrada exitosamente'); } else { console.error('Error al cerrar sesión'); }}).catch(error => console.error('Error durante el cierre de sesión:', error));Gestión de Usuarios
1. Obtener Perfil de Usuario Actual
Ejemplo con cURL:
curl -X GET http://localhost:3000/api/v1/users/me \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."Ejemplo con JavaScript:
fetch('http://localhost:3000/api/v1/users/me', { method: 'GET', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, },}).then(response => response.json()).then(data => console.log('Perfil de usuario:', data)).catch(error => console.error('Error al obtener perfil:', error));2. Actualizar Perfil de Usuario
Ejemplo con cURL:
curl -X PUT http://localhost:3000/api/v1/users/me \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "first_name": "Actualizado", "last_name": "Apellido" }'Ejemplo con JavaScript:
fetch('http://localhost:3000/api/v1/users/me', { method: 'PUT', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ first_name: 'Actualizado', last_name: 'Apellido' }),}).then(response => response.json()).then(data => console.log('Perfil actualizado:', data)).catch(error => console.error('Error al actualizar perfil:', error));3. Listar Todos los Usuarios (Solo Administrador)
Ejemplo con cURL:
curl -X GET "http://localhost:3000/api/v1/users?page=1&per_page=20" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."Ejemplo con JavaScript:
fetch('http://localhost:3000/api/v1/users?page=1&per_page=20', { method: 'GET', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, },}).then(response => response.json()).then(data => console.log('Lista de usuarios:', data)).catch(error => console.error('Error al obtener usuarios:', error));Gestión de Claves API
1. Crear una Clave API
Ejemplo con cURL:
curl -X POST http://localhost:3000/api/v1/api-keys \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "name": "Clave API para Mi Servicio", "expires_at": "2025-12-31T23:59:59Z" }'Respuesta:
{ "id": "8a7b6c5d-4e3f-2a1b-0c9d-8e7f6a5b4c3d", "user_id": "5f8d0d55-8b96-4536-8c34-781a9a3e9a9b", "name": "Clave API para Mi Servicio", "key": "sk-Avery1LongRandomAPIKeyStringThatShouldBeStoredSafely", "prefix": "sk-Avery", "is_active": true, "expires_at": "2025-12-31T23:59:59Z", "created_at": "2023-06-01T12:34:56Z", "updated_at": "2023-06-01T12:34:56Z"}Importante: La clave API completa (campo key) solo se devuelve una vez al crearla. Guárdala de forma segura ya que no podrás recuperarla más tarde.
2. Listar tus Claves API
Ejemplo con cURL:
curl -X GET http://localhost:3000/api/v1/api-keys \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."3. Añadir Permisos a Clave API
Ejemplo con cURL:
curl -X POST http://localhost:3000/api/v1/api-keys/8a7b6c5d-4e3f-2a1b-0c9d-8e7f6a5b4c3d/permissions \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "permission_id": "5f8d0d55-8b96-4536-8c34-781a9a3e9a9b" }'4. Usar una Clave API para Autenticación
En lugar de usar tokens JWT, puedes autenticarte con una clave API:
Ejemplo con cURL:
curl -X GET http://localhost:3000/api/v1/users/me \ -H "X-API-Key: sk-Avery1LongRandomAPIKeyStringThatShouldBeStoredSafely"Ejemplo con JavaScript:
fetch('http://localhost:3000/api/v1/users/me', { method: 'GET', headers: { 'X-API-Key': 'sk-Avery1LongRandomAPIKeyStringThatShouldBeStoredSafely', },}).then(response => response.json()).then(data => console.log('Perfil de usuario:', data)).catch(error => console.error('Error al obtener perfil:', error));Gestión de Roles y Permisos
1. Listar Todos los Roles
Ejemplo con cURL:
curl -X GET http://localhost:3000/api/v1/roles \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."2. Crear un Nuevo Rol (Solo Administrador)
Ejemplo con cURL:
curl -X POST http://localhost:3000/api/v1/roles \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "name": "editor", "description": "Puede editar contenido pero no gestionar usuarios" }'3. Añadir Permiso a Rol (Solo Administrador)
Ejemplo con cURL:
curl -X POST http://localhost:3000/api/v1/roles/8a7b6c5d-4e3f-2a1b-0c9d-8e7f6a5b4c3d/permissions \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "permission_id": "5f8d0d55-8b96-4536-8c34-781a9a3e9a9b" }'4. Asignar Rol a Usuario (Solo Administrador)
Ejemplo con cURL:
curl -X POST http://localhost:3000/api/v1/users/8a7b6c5d-4e3f-2a1b-0c9d-8e7f6a5b4c3d/roles \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "role_id": "5f8d0d55-8b96-4536-8c34-781a9a3e9a9b" }'Ejemplos de Manejo de Errores
1. Error de Validación
Solicitud:
curl -X POST http://localhost:3000/api/v1/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "email-invalido", "password": "corta", "first_name": "Juan", "last_name": "Pérez" }'Respuesta:
{ "error": "Validación fallida", "fields": { "email": "debe ser una dirección de email válida", "password": "debe tener al menos 8 caracteres" }}2. Error de Autenticación
Solicitud:
curl -X GET http://localhost:3000/api/v1/users/meRespuesta:
{ "error": "No autorizado: falta token de autenticación", "status": 401}3. Error de Límite de Tasa
Cuando se exceden los límites de tasa:
Respuesta:
{ "error": "Límite de tasa excedido", "status": 429}Utilidades de Ayuda
Utilidad de Autenticación JavaScript
Aquí hay una utilidad JavaScript simple para manejar la autenticación:
class AuthService { constructor(apiUrl) { this.apiUrl = apiUrl; this.accessToken = localStorage.getItem('access_token'); this.refreshToken = localStorage.getItem('refresh_token'); }
isAuthenticated() { return !!this.accessToken; }
async login(email, password) { const response = await fetch(`${this.apiUrl}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email, password }), });
if (!response.ok) { const error = await response.json(); throw new Error(error.error || 'Error al iniciar sesión'); }
const data = await response.json(); this.accessToken = data.access_token; this.refreshToken = data.refresh_token;
localStorage.setItem('access_token', this.accessToken); localStorage.setItem('refresh_token', this.refreshToken);
return data; }
async logout() { if (!this.refreshToken) return;
try { await fetch(`${this.apiUrl}/auth/logout`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ refresh_token: this.refreshToken }), }); } catch (error) { console.error('Error al cerrar sesión:', error); } finally { // Eliminar tokens independientemente del éxito al cerrar sesión this.accessToken = null; this.refreshToken = null; localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); } }
async refreshAccessToken() { if (!this.refreshToken) throw new Error('No hay token de refresco disponible');
const response = await fetch(`${this.apiUrl}/auth/refresh`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ refresh_token: this.refreshToken }), });
if (!response.ok) { // Si la renovación falla, cerrar sesión this.logout(); throw new Error('Error al renovar token'); }
const data = await response.json(); this.accessToken = data.access_token; this.refreshToken = data.refresh_token;
localStorage.setItem('access_token', this.accessToken); localStorage.setItem('refresh_token', this.refreshToken);
return data; }
async fetchWithAuth(url, options = {}) { const headers = { ...options.headers, 'Authorization': `Bearer ${this.accessToken}`, };
let response = await fetch(url, { ...options, headers });
// Si no está autorizado, intentar renovar token y reintentar la solicitud if (response.status === 401 && this.refreshToken) { try { await this.refreshAccessToken(); // Actualizar encabezados con nuevo token headers.Authorization = `Bearer ${this.accessToken}`; // Reintentar la solicitud response = await fetch(url, { ...options, headers }); } catch (error) { console.error('Error al renovar token:', error); throw error; } }
return response; }}
// Uso:const auth = new AuthService('http://localhost:3000/api/v1');
async function loginUser(email, password) { try { await auth.login(email, password); console.log('Inicio de sesión exitoso'); } catch (error) { console.error('Error al iniciar sesión:', error); }}
async function getUserProfile() { try { const response = await auth.fetchWithAuth(`${auth.apiUrl}/users/me`); if (!response.ok) throw new Error('Error al obtener perfil'); const profile = await response.json(); console.log('Perfil de usuario:', profile); return profile; } catch (error) { console.error('Error al obtener perfil:', error); }}Ejemplo de Cliente Go
Aquí hay un cliente Go simple para la API:
package main
import ( "bytes" "encoding/json" "errors" "fmt" "net/http")
// AuthClient representa un cliente para la API de autenticacióntype AuthClient struct { BaseURL string AccessToken string RefreshToken string HTTPClient *http.Client}
// NewAuthClient crea un nuevo cliente de autenticaciónfunc NewAuthClient(baseURL string) *AuthClient { return &AuthClient{ BaseURL: baseURL, HTTPClient: &http.Client{}, }}
// TokenResponse representa la respuesta de los endpoints de login y refreshtype TokenResponse struct { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` ExpiresIn int `json:"expires_in"`}
// Login autentica a un usuariofunc (c *AuthClient) Login(email, password string) error { // Crear cuerpo de la solicitud requestBody, err := json.Marshal(map[string]string{ "email": email, "password": password, }) if err != nil { return err }
// Realizar la solicitud resp, err := c.HTTPClient.Post( c.BaseURL+"/auth/login", "application/json", bytes.NewBuffer(requestBody), ) if err != nil { return err } defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { var errorResp map[string]interface{} json.NewDecoder(resp.Body).Decode(&errorResp) return fmt.Errorf("error al iniciar sesión: %v", errorResp["error"]) }
// Analizar la respuesta var tokenResp TokenResponse if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { return err }
// Guardar tokens c.AccessToken = tokenResp.AccessToken c.RefreshToken = tokenResp.RefreshToken return nil}
// AuthenticatedRequest realiza una solicitud autenticadafunc (c *AuthClient) AuthenticatedRequest(method, path string, body interface{}) (*http.Response, error) { if c.AccessToken == "" { return nil, errors.New("no autenticado") }
var bodyReader *bytes.Buffer if body != nil { bodyData, err := json.Marshal(body) if err != nil { return nil, err } bodyReader = bytes.NewBuffer(bodyData) }
// Crear solicitud req, err := http.NewRequest(method, c.BaseURL+path, bodyReader) if err != nil { return nil, err }
// Establecer encabezados req.Header.Set("Authorization", "Bearer "+c.AccessToken) if body != nil { req.Header.Set("Content-Type", "application/json") }
// Realizar la solicitud resp, err := c.HTTPClient.Do(req) if err != nil { return nil, err }
// Si no está autorizado, intentar renovar token if resp.StatusCode == http.StatusUnauthorized && c.RefreshToken != "" { resp.Body.Close() // Cerrar la respuesta 401
// Intentar renovar token err = c.RefreshTokens() if err != nil { return nil, fmt.Errorf("error al renovar token: %w", err) }
// Reintentar la solicitud con nuevo token req.Header.Set("Authorization", "Bearer "+c.AccessToken) return c.HTTPClient.Do(req) }
return resp, nil}
// RefreshTokens renueva el token de accesofunc (c *AuthClient) RefreshTokens() error { if c.RefreshToken == "" { return errors.New("no hay token de refresco disponible") }
// Crear cuerpo de la solicitud requestBody, err := json.Marshal(map[string]string{ "refresh_token": c.RefreshToken, }) if err != nil { return err }
// Realizar la solicitud resp, err := c.HTTPClient.Post( c.BaseURL+"/auth/refresh", "application/json", bytes.NewBuffer(requestBody), ) if err != nil { return err } defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { // Limpiar tokens en caso de error de renovación c.AccessToken = "" c.RefreshToken = "" var errorResp map[string]interface{} json.NewDecoder(resp.Body).Decode(&errorResp) return fmt.Errorf("error al renovar token: %v", errorResp["error"]) }
// Analizar la respuesta var tokenResp TokenResponse if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { return err }
// Guardar nuevos tokens c.AccessToken = tokenResp.AccessToken c.RefreshToken = tokenResp.RefreshToken return nil}
// GetUserProfile obtiene el perfil del usuario actualfunc (c *AuthClient) GetUserProfile() (map[string]interface{}, error) { resp, err := c.AuthenticatedRequest("GET", "/users/me", nil) if err != nil { return nil, err } defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { var errorResp map[string]interface{} json.NewDecoder(resp.Body).Decode(&errorResp) return nil, fmt.Errorf("error al obtener perfil: %v", errorResp["error"]) }
var profile map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&profile); err != nil { return nil, err }
return profile, nil}
// Ejemplo de usofunc main() { client := NewAuthClient("http://localhost:3000/api/v1")
// Iniciar sesión if err != nil { fmt.Println("Error de inicio de sesión:", err) return }
// Obtener perfil profile, err := client.GetUserProfile() if err != nil { fmt.Println("Error al obtener perfil:", err) return }
fmt.Println("Perfil de usuario:", profile)}