Su API bajo ataque: por qué la limitación de velocidad y el throttling son imprescindibles para el desarrollador Swift
\n\nImagine: lanzó una aplicación increíble en Swift, los usuarios están encantados, los servidores funcionan perfectamente. Pero de repente, el colapso. Alguien ejecutó un script que golpea su API con miles de solicitudes por segundo. O simplemente un usuario activo presiona el botón "Actualizar" más rápido de lo que usted puede procesar los datos. El resultado: lentitud, caída del servidor y reseñas negativas.
\n\n¿Le suena familiar? Entonces este artículo es para usted. Analizaremos la limitación de velocidad y el throttling en Swift: técnicas que salvarán su backend y harán que la aplicación sea estable. Aprenderá cómo implementar la limitación de solicitudes en Swift del lado del cliente, utilizando enfoques modernos con async/await, y qué patrones realmente funcionan.
\n\nRate limiting vs Throttling: ¿cuál es la diferencia?
\n\nAntes de escribir código, aclaremos los términos. Muchos confunden estos conceptos, aunque resuelven diferentes problemas.
\n\nRate limiting (limitación de velocidad)
\nEs un límite estricto: "No más de N solicitudes por período". Si se excede el límite, la solicitud es rechazada. El servidor generalmente devuelve 429 Too Many Requests. Ejemplo: permite no más de 100 solicitudes por minuto desde una misma IP.
Throttling (estrangulamiento)
\nEs un mecanismo más suave: las solicitudes no se bloquean, sino que se ponen en cola y se ejecutan a una frecuencia determinada. Imagine que su API solo puede procesar 5 solicitudes por segundo. El throttling las pondrá en cola y las enviará a la velocidad necesaria, sin sobrecargar el servidor.
\n\nEn Swift, ambos enfoques se implementan de manera diferente. Veamos las mejores prácticas.
\n\nImplementaciones prácticas de rate limiting en Swift
\n\n1. Throttling simple con temporizador (GCD)
\n\nLa forma más sencilla de limitar solicitudes en Swift es usar DispatchQueue y un temporizador. Aquí hay un ejemplo que garantiza que las solicitudes se envíen no más de una vez por segundo:
\n\nimport Foundation\n\nfinal class RequestThrottler {\n private let queue = DispatchQueue(label: "com.app.throttle")\n private var lastRequestTime: Date = .distantPast\n private let minimumInterval: TimeInterval\n \n init(interval: TimeInterval = 1.0) {\n self.minimumInterval = interval\n }\n \n func performThrottledRequest(block: @escaping () -> Void) {\n queue.sync {\n let now = Date()\n if now.timeIntervalSince(lastRequestTime) >= minimumInterval {\n lastRequestTime = now\n DispatchQueue.main.async {\n block()\n }\n } else {\n print("Solicitud rechazada: demasiado frecuente")\n }\n }\n }\n}\n\n// Uso\nlet throttler = RequestThrottler(interval: 2.0)\nthrottler.performThrottledRequest {\n // Su solicitud API\n print("Solicitud ejecutada")\n}\n\nEste enfoque es simple, pero no ideal: simplemente descarta las solicitudes "sobrantes". Para muchos escenarios es suficiente, pero si necesita mantener el orden y garantizar la ejecución, siga leyendo.
\n\n2. Rate limiter con cola (async/await)
\n\nCon la llegada de Swift async/await tenemos una forma elegante de implementar un swift rate limiter con soporte de cola. Así es como se ve:
\n\nimport Foundation\n\nactor RateLimiter {\n private let maxRequests: Int\n private let perSecond: Double\n private var requestTimestamps: [Date] = []\n private var pendingTasks: [CheckedContinuation] = []\n private var isProcessing = false\n \n init(maxRequests: Int, perSecond: Double) {\n self.maxRequests = maxRequests\n self.perSecond = perSecond\n }\n \n func waitForSlot() async throws {\n try await withCheckedThrowingContinuation { continuation in\n pendingTasks.append(continuation)\n if