Introducción
Las aplicaciones modernas de iOS y macOS rara vez prescinden de la interacción con servidores remotos. Ya sea cargar datos de un feed de noticias, enviar un formulario de registro o sincronizar archivos, todas estas operaciones requieren una implementación adecuada de un cliente HTTP. En el ecosistema Swift, el desarrollador tiene a su disposición el potente framework integrado URLSession, que cada año se vuelve más conveniente gracias a la incorporación de async/await.
En este artículo, analizaremos cómo crear correctamente solicitudes HTTP en Swift, comenzando con las estructuras básicas y terminando con técnicas avanzadas de manejo de errores y serialización de datos. Aprenderá a escribir código de red limpio, seguro y eficiente para sus aplicaciones.
Fundamentos de URLSession: primera solicitud HTTP
La clase URLSession es la base de cualquier trabajo de red en Swift. Gestiona la configuración, el almacenamiento en caché, las sesiones y la ejecución directa de las solicitudes. Veamos una solicitud GET simple para obtener datos de un servidor.
Creación de una solicitud GET simple
import Foundation
// 1. Creamos la URLguard let url = URL(string: "https://api.example.com/users") else { print("URL inválida") return}
// 2. Creamos la solicitud (por defecto GET)var request = URLRequest(url: url)request.httpMethod = "GET"request.setValue("application/json", forHTTPHeaderField: "Accept")
// 3. Creamos la sesiónlet session = URLSession.shared
// 4. Ejecutamos la solicitud (método antiguo con closure)let task = session.dataTask(with: request) { data, response, error in if let error = error { print("Error en la solicitud: \\(error.localizedDescription)") return } guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { print("El servidor devolvió un error") return } if let data = data, let jsonString = String(data: data, encoding: .utf8) { print("Datos recibidos: \\(jsonString)") }}task.resume() // ¡Importante! Iniciamos la tareaPuntos clave: siempre verifique el estado de la respuesta (200...299), no olvide llamar a resume() y maneje los posibles errores. En proyectos reales, este código generalmente se extrae en una capa de servicio separada.
Enfoque moderno: async/await
A partir de Swift 5.5, es posible usar async/await, lo que hace que el código sea mucho más legible y elimina la "pirámide de closures".
func fetchUsers() async throws -> Data { guard let url = URL(string: "https://api.example.com/users") else { throw URLError(.badURL) } var request = URLRequest(url: url) request.httpMethod = "GET" request.setValue("application/json", forHTTPHeaderField: "Accept") let (data, response) = try await URLSession.shared.data(for: request) guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { throw URLError(.badServerResponse) } return data}Este código se puede llamar desde cualquier función o tarea asíncrona, lo que simplifica significativamente la lógica.
Trabajo con JSON: Codable y modelos de datos
Rara vez los datos llegan en formato "crudo". La mayoría de las veces trabajamos con JSON. Swift ofrece una solución elegante: el protocolo Codable (que combina Encodable y Decodable).
Creación del modelo y decodificación
// 1. Definimos la estructura de datosstruct User: Codable { let id: Int let name: String let email: String}
// 2. Función asíncrona para obtener un array de usuariosfunc fetchUsers() async throws -> [User] { let data = try await fetchUsersData() // del ejemplo anterior let decoder = JSONDecoder() return try decoder.decode