Saltar al contenido

Redes: URLSession y Codable

Consume APIs REST de forma moderna: peticiones async con URLSession y decodificación automática de JSON con Codable. De la nube a tu app, sin dolor.

Casi ninguna app vive aislada: consultan el tiempo, cargan un feed, sincronizan con un servidor. Con async/await y Codable, hacer una petición de red y convertir la respuesta JSON en objetos Swift es sorprendentemente limpio.

  • Hacer una petición GET con URLSession y await.
  • Decodificar JSON automáticamente con Codable.
  • Manejar errores de red.
  • Un ejemplo completo de principio a fin.

Codable: JSON ⇄ Swift

Un tipo que conforma a Codable se convierte a/desde JSON solo. Si los nombres coinciden con las claves del JSON, no escribes nada más:

SWIFT
struct Publicacion: Codable, Identifiable {    let id: Int    let title: String    let body: String}

Para un JSON {"id": 1, "title": "Hola", "body": "…"}, este struct encaja directo. Si las claves difieren (JSON en snake_case), usas CodingKeys o un decoder con .convertFromSnakeCase.

La petición con URLSession

URLSession moderno es async: pides los datos con await y los tienes:

SWIFT
func cargarPublicaciones() async throws -> [Publicacion] {    let url = URL(string: "https://jsonplaceholder.typicode.com/posts")!    let (datos, respuesta) = try await URLSession.shared.data(from: url)    guard let http = respuesta as? HTTPURLResponse, http.statusCode == 200 else {        throw ErrorRed.codigoInvalido    }    return try JSONDecoder().decode([Publicacion].self, from: datos)}enum ErrorRed: Error { case codigoInvalido }

Tres pasos: pides los datos (await), compruebas el código HTTP, decodificas el JSON. El try propaga cualquier fallo (Nivel 1).

Conectarlo a la interfaz

Junta todo con el patrón .task y un modelo @Observable (Niveles 3 y 5):

SWIFT
@Observableclass Feed {    var publicaciones: [Publicacion] = []    var cargando = false    var error: String?    func cargar() async {        cargando = true        defer { cargando = false }        do {            publicaciones = try await cargarPublicaciones()        } catch {            self.error = "No se pudo cargar: \(error.localizedDescription)"        }    }}struct FeedView: View {    @State private var feed = Feed()    var body: some View {        List(feed.publicaciones) { post in            VStack(alignment: .leading) {                Text(post.title).font(.headline)                Text(post.body).font(.caption).foregroundStyle(.secondary)            }        }        .overlay { if feed.cargando { ProgressView() } }        .task { await feed.cargar() }    }}

Todo el curso encaja aquí

Detente a ver cuántas piezas se juntan en este ejemplo: Codable (Nivel 1) decodifica el JSON, async/await (5.1) hace la petición sin bloquear, @Observable (3.1) mantiene el estado, .task (5.1) lo carga al aparecer y lo cancela al salir, do/catch (1.5) maneja el error, y List (2.5) lo muestra. Esto no es un truco aislado: es cómo se construye de verdad la pantalla de datos de una app real. Cuando estas piezas te salen juntas y con naturalidad, ya piensas como un desarrollador iOS.

Modela para lo que puede fallar

La red es el reino de lo incierto: no hay conexión, el servidor devuelve un error, el JSON viene raro. Un principiante asume el camino feliz; un profesional modela los tres estados —cargando, éxito, error— desde el principio (¿recuerdas los enums con valores asociados del Nivel 1?). Tu interfaz debe tener siempre respuesta para “está cargando” y “algo falló”, no solo para “todo bien”.

Trae datos de internet

  1. Define un struct Codable que encaje con una API pública (prueba jsonplaceholder.typicode.com).
  2. Escribe una función async throws que descargue y decodifique el JSON.
  3. Crea un modelo @Observable con estados de carga y error.
  4. Muéstralo en una List cargando con .task.
  5. Añade un ProgressView mientras carga y un mensaje si falla.