Introducción: ¿Por qué Swift es adecuado para una API REST?
\n\nCuando se habla de desarrollo de servidores, Swift no es el primer lenguaje que viene a la mente. Sin embargo, con la aparición del framework Vapor (y su alternativa, Kitura), Swift se ha convertido en una herramienta completa para crear API REST. ¿Por qué usar Swift en el servidor? En primer lugar, es un lenguaje unificado para iOS, macOS y backend: puedes reutilizar modelos de datos. En segundo lugar, Swift es rápido, seguro y tiene un excelente soporte para asincronía mediante async/await.
\n\nEn esta guía crearemos una API REST simple para gestionar una lista de tareas (Todo list) en Swift utilizando el framework Vapor. Aprenderás a configurar el servidor, crear rutas, trabajar con JSON y probar la API. Todo el proceso tomará unos 30 minutos.
\n\nPaso 1: Instalación y configuración del proyecto
\n\nAntes de escribir código, necesitas instalar Vapor Toolbox, una utilidad de línea de comandos para crear y gestionar proyectos Vapor.
\n\nInstalación de Vapor Toolbox
\nAbre la terminal y ejecuta:
\nbrew install vapor\nSi no tienes Homebrew, instálalo desde brew.sh.
\n\nCreación de un nuevo proyecto
\nCrearemos un nuevo proyecto llamado TodoAPI:
vapor new TodoAPI -n\ncd TodoAPI\nLa bandera -n significa "sin ejemplo": obtendremos una plantilla limpia.
Inicio del servidor
\nAbre el proyecto en Xcode:
\nopen Package.swift\nSelecciona el esquema Run y presiona Cmd+R. Después de unos segundos, el servidor se iniciará en http://127.0.0.1:8080. Abre el navegador: deberías ver un mensaje de bienvenida de Vapor.
Paso 2: Creación del modelo de datos
\n\nNuestra API gestionará tareas. Cada tarea tiene un ID, un título y un estado de finalización (completada/no completada).
\n\nCrearemos el modelo Todo. En Vapor, los modelos son estructuras comunes que cumplen con el protocolo Content (para serialización a JSON) y Codable.
Crea el archivo Sources/App/Models/Todo.swift:
\nimport Vapor\n\nstruct Todo: Content, Codable {\n var id: UUID?\n var title: String\n var isCompleted: Bool\n \n init(id: UUID? = nil, title: String, isCompleted: Bool = false) {\n self.id = id\n self.title = title\n self.isCompleted = isCompleted\n }\n}\n\nTen en cuenta: id es un UUID opcional. Lo generaremos en el servidor al crear la tarea.
Paso 3: Creación del almacenamiento y el controlador
\n\nPara simplificar, almacenaremos las tareas en memoria (en un array). En un proyecto real usarías una base de datos (Fluent ORM), pero para una demo de 30 minutos es excesivo.
\n\nAlmacenamiento (In-Memory Store)
\nCrea el archivo Sources/App/Controllers/TodoStore.swift:
\nimport Vapor\n\nfinal class TodoStore {\n private var todos: [Todo] = []\n private let lock = NSLock()\n \n func getAll() -> [Todo] {\n lock.lock()\n defer { lock.unlock() }\n return todos\n }\n \n func get(id: UUID) -> Todo? {\n lock.lock()\n defer { lock.unlock() }\n return todos.first { $0.id == id }\n }\n \n func create(_ todo: inout Todo) -> Todo {\n lock.lock()\n defer { lock.unlock() }\n todo.id = UUID()\n todos.append(todo)\n return todo\n }\n \n func update(id: UUID, with updatedTodo: Todo) -> Todo? {\n lock.lock()\n defer { lock.unlock() }\n guard let index = todos.firstIndex(where: { $0.id == id }) else { return nil }\n var mutableTodo = updatedTodo\n mutableTodo.id = id\n todos[index] = mutableTodo\n return mutableTodo\n }\n \n func delete(id: UUID) ->