Saltar al contenido principal

API Endpoints

En el vasto ecosistema de KodeChain, donde múltiples componentes interactúan en armonía, la API REST emerge como el lenguaje universal que permite la comunicación entre nodos, aplicaciones y usuarios. Implementada a través de Gin y documentada con Swagger, esta interfaz transforma operaciones técnicas complejas en endpoints HTTP intuitivos y bien definidos.

La Arquitectura de la API

Gin Framework: El Motor HTTP

// En api/server.go
func NewServer() *Server {
gin.SetMode(gin.ReleaseMode)
r := gin.Default()

// Middleware de logging
r.Use(gin.Logger())
r.Use(gin.Recovery())

// Configuración de CORS
r.Use(cors.Default())

return &Server{
router: r,
endpoints: make(map[string]Endpoint),
}
}

Gin proporciona la base sólida sobre la que se construye toda la comunicación HTTP del sistema.

Estructura de Endpoints Organizada

// En api/endpoints/
├── blockchain.go // Estado de la blockchain
├── transactions.go // Gestión de transacciones
├── validator_registration.go // Registro de validadores
├── staking.go // Sistema de staking
├── sync.go // Sincronización
└── upnp.go // Configuración UPnP

Cada archivo se enfoca en un dominio específico, manteniendo la organización y mantenibilidad.

Categorías de Endpoints

Blockchain Status

GET /api/blockchain/status

Obtiene el estado general de ambas cadenas (DPOS y PBFT).

func (s *Server) getBlockchainStatus(c *gin.Context) {
status := map[string]interface{}{
"dpos": s.getChainStatus("DPOS"),
"pbft": s.getChainStatus("PBFT"),
"timestamp": time.Now().Unix(),
}
c.JSON(200, status)
}

Respuesta:

{
"dpos": {
"height": 1500,
"last_block": "0xabc123...",
"validators": 6,
"status": "active"
},
"pbft": {
"height": 1498,
"last_block": "0xdef456...",
"validators": 4,
"status": "active"
},
"timestamp": 1640995200
}

Gestión de Transacciones

POST /api/transaction/create

Crea una nueva transacción y la añade al mempool.

func (s *Server) createTransaction(c *gin.Context) {
var req CreateTransactionRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}

// Validar transacción
if err := s.validateTransaction(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}

// Crear y firmar transacción
tx := s.createTransactionFromRequest(&req)

// Añadir al mempool
if err := s.mempool.AddTransaction(tx); err != nil {
c.JSON(500, gin.H{"error": "Failed to add to mempool"})
return
}

c.JSON(201, gin.H{
"success": true,
"transaction_hash": tx.Hash,
"mempool_size": s.mempool.Size(),
})
}

Parámetros:

{
"from": "0x1000000000000000000000000000000000000001",
"to": "0x1000000000000000000000000000000000000002",
"amount": 1000000000000000000,
"type": "transfer",
"data": ""
}

Sistema de Staking

POST /api/staking/delegate/register

Registra un nuevo validador en el sistema de staking.

func (s *Server) registerDelegate(c *gin.Context) {
var req DelegateRegistrationRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}

// Verificar stake mínimo
if req.StakeAmount < MIN_STAKE {
c.JSON(400, gin.H{"error": "Stake amount below minimum"})
return
}

// Registrar en staking contract
nodeID, err := s.stakingContract.RegisterDelegate(
req.DelegateAddress,
req.StakeAmount,
req.ConsensusType,
)

if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}

c.JSON(200, gin.H{
"success": true,
"node_id": nodeID,
"message": "Delegate registered successfully",
})
}

Sincronización entre Nodos

GET /api/sync/height

Obtiene la altura actual de la blockchain para un tipo de consenso específico.

func (s *Server) getBlockHeight(c *gin.Context) {
consensusType := c.GetHeader("X-Consensus-Type")
if consensusType == "" {
c.JSON(400, gin.H{"error": "X-Consensus-Type header required"})
return
}

height, err := s.blockchain.GetHeight(consensusType)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}

c.JSON(200, gin.H{
"height": height,
"consensus_type": consensusType,
"timestamp": time.Now().Unix(),
})
}

Headers requeridos:

  • X-Consensus-Type: "DPOS" o "PBFT"

Middleware y Seguridad

Rate Limiting

func RateLimitMiddleware() gin.HandlerFunc {
limiter := tollbooth.NewLimiter(10, nil) // 10 requests por segundo
return func(c *gin.Context) {
httpError := tollbooth.LimitByRequest(limiter, c.Writer, c.Request)
if httpError != nil {
c.JSON(httpError.StatusCode, gin.H{
"error": "Rate limit exceeded",
"retry_after": httpError.Message,
})
c.Abort()
return
}
c.Next()
}
}

Protege contra abusos y ataques de denegación de servicio.

Autenticación y Autorización

func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
auth := c.GetHeader("Authorization")
if auth == "" {
c.JSON(401, gin.H{"error": "Authorization header required"})
c.Abort()
return
}

// Verificar token de autenticación
if !s.validateAuthToken(auth) {
c.JSON(403, gin.H{"error": "Invalid authentication token"})
c.Abort()
return
}

c.Next()
}
}

Asegura que solo usuarios autorizados puedan acceder a endpoints sensibles.

Headers Especiales

X-Consensus-Type

Especifica qué cadena (DPOS o PBFT) debe manejar la solicitud.

consensusType := c.GetHeader("X-Consensus-Type")
switch consensusType {
case "DPOS":
// Manejar con lógica DPOS
case "PBFT":
// Manejar con lógica PBFT
default:
c.JSON(400, gin.H{"error": "Invalid consensus type"})
return
}

Content-Type

Siempre debe ser application/json para requests con body.

r.POST("/api/transaction/create", func(c *gin.Context) {
if c.ContentType() != "application/json" {
c.JSON(400, gin.H{"error": "Content-Type must be application/json"})
return
}
// Procesar request...
})

Manejo de Errores

Estructura de Respuestas de Error

type ErrorResponse struct {
Error string `json:"error"`
Code int `json:"code"`
Details string `json:"details,omitempty"`
}

Códigos de Estado HTTP

  • 200 OK: Operación exitosa
  • 201 Created: Recurso creado exitosamente
  • 400 Bad Request: Parámetros inválidos
  • 401 Unauthorized: Autenticación requerida
  • 403 Forbidden: Permisos insuficientes
  • 404 Not Found: Recurso no encontrado
  • 405 Method Not Allowed: Método HTTP no soportado
  • 409 Conflict: Conflicto con estado actual
  • 500 Internal Server Error: Error del servidor

Documentación con Swagger

Generación Automática

//go:generate swag init -g main.go -o docs/

El comando genera automáticamente la documentación Swagger desde los comentarios en el código.

Comentarios de Documentación

// getBlockchainStatus godoc
// @Summary Get blockchain status
// @Description Get the status of both DPOS and PBFT chains
// @Tags blockchain
// @Accept json
// @Produce json
// @Success 200 {object} map[string]interface{}
// @Router /api/blockchain/status [get]
func (s *Server) getBlockchainStatus(c *gin.Context) {
// Implementación...
}

Los comentarios especiales generan la documentación Swagger automáticamente.

Testing de Endpoints

Tests Unitarios

func TestCreateTransaction(t *testing.T) {
// Setup
server := NewServer()
req := CreateTransactionRequest{
From: "0x1000...001",
To: "0x1000...002",
Amount: 1000000000000000000,
}

// Execute
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = &http.Request{
Method: "POST",
Body: io.NopCloser(strings.NewReader(toJSON(req))),
}

server.createTransaction(c)

// Assert
assert.Equal(t, 201, w.Code)

var response map[string]interface{}
json.Unmarshal(w.Body.Bytes(), &response)
assert.True(t, response["success"].(bool))
}

Tests de Integración

func TestFullTransactionFlow(t *testing.T) {
// Iniciar servidor completo
server := setupTestServer()

// Crear transacción
txResp := createTestTransaction(server)
assert.NotEmpty(t, txResp["transaction_hash"])

// Verificar en mempool
mempoolResp := getMempoolStats(server)
assert.Greater(t, mempoolResp["size"], 0)

// Esperar minado
time.Sleep(3 * time.Second)

// Verificar en blockchain
blockResp := getLatestBlock(server)
assert.Contains(t, blockResp["transactions"], txResp["transaction_hash"])
}

Monitoreo y Métricas

Métricas de Rendimiento

func (s *Server) metricsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path

c.Next()

duration := time.Since(start)
status := c.Writer.Status()

// Registrar métricas
s.metrics.RecordRequest(path, status, duration)
}
}

Health Checks

func (s *Server) healthCheck(c *gin.Context) {
health := map[string]interface{}{
"status": "healthy",
"timestamp": time.Now().Unix(),
"version": s.version,
"uptime": time.Since(s.startTime).String(),
}

// Verificar componentes críticos
if err := s.checkDatabase(); err != nil {
health["database"] = "unhealthy"
health["status"] = "degraded"
}

if err := s.checkConsensus(); err != nil {
health["consensus"] = "unhealthy"
health["status"] = "degraded"
}

statusCode := 200
if health["status"] != "healthy" {
statusCode = 503
}

c.JSON(statusCode, health)
}

El Rol en la Arquitectura

Puerta de Entrada al Sistema

La API REST actúa como la interfaz principal entre:

  • Usuarios finales: Aplicaciones web y móviles
  • Otros nodos: Comunicación P2P
  • Herramientas de desarrollo: SDKs y bibliotecas
  • Sistemas de monitoreo: Dashboards y alertas

Abstracción de Complejidad

// Para el usuario: simple llamada HTTP
POST /api/transaction/create

// Detrás de escena: compleja lógica distribuida
func createTransaction() {
// Validar transacción
// Verificar balances
// Firmar con criptografía cuántica
// Añadir al mempool distribuido
// Propagar a otros nodos
// Esperar confirmación de consenso
}

Escalabilidad y Mantenibilidad

La arquitectura modular permite:

  • Añadir nuevos endpoints: Sin afectar existentes
  • Versionado de API: Soporte para múltiples versiones
  • Rate limiting granular: Por endpoint o usuario
  • Logging detallado: Para debugging y auditoría

El Arte de la Comunicación

Cada endpoint, cada parámetro, cada código de respuesta representa un contrato entre el sistema y sus usuarios. La API REST de KodeChain no solo expone funcionalidad; establece un lenguaje común que hace que la complejidad de la blockchain sea accesible y utilizable.

Desde el primer gin.Default() hasta la respuesta JSON final, la API transforma operaciones técnicas en interacciones intuitivas, permitiendo que desarrolladores y usuarios construyan sobre KodeChain con confianza y facilidad.