Vapor 4 en 2026: servidor HTTP en Swift puro sin Node.js

Swift no es solo para apps de iOS y macOS. Desde que Apple liberó el lenguaje como open source en 2015 y publicó soporte oficial para Linux, existe un ecosistema de backend Swift real. Vapor es el framework web más maduro de ese ecosistema: lleva activo desde 2016, y la versión 4 (lanzada en 2020 y mantenida activamente) es la base de muchos servicios en producción. En 2026, con Swift 6 y structured concurrency integrados, Vapor 4 es una opción seria para backend HTTP cuando ya tienes equipos con experiencia en Swift.

Por qué Swift en servidor

El argumento principal es compartir código entre cliente y servidor. Si tu app iOS usa modelos Swift con Codable, esos mismos structs pueden usarse en el backend sin ninguna duplicación. El tipado estático de Swift también elimina una clase entera de errores en tiempo de ejecución que son habituales en Node.js.

El rendimiento es comparable a Go para cargas de trabajo típicas de APIs REST, aunque sin el ecosistema de librerías de Go o la adopción masiva que tiene. Si buscas un lenguaje de servidor con años de madurez y un ecosistema enorme, Go o Rust son mejores opciones. Si tu equipo ya sabe Swift y quieres compartir lógica con el cliente, Vapor tiene sentido.

Instalación y primer proyecto

Vapor necesita Swift 5.9 o superior y funciona en macOS y Linux. La forma más sencilla de empezar es con la CLI de Vapor:

# macOS con Homebrew
brew install vapor

# Crear nuevo proyecto
vapor new MiAPI --template=api
cd MiAPI
swift run

El servidor arranca en http://localhost:8080. La estructura del proyecto usa Swift Package Manager: no hay configuración externa, todo está en Package.swift.

Rutas y controladores

Las rutas en Vapor se definen en configure.swift o en controladores separados. La sintaxis es fluida y se lee bien:

import Vapor

func routes(_ app: Application) throws {
    // Ruta simple
    app.get("saludo") { req async in
        "Hola desde Vapor"
    }

    // Ruta con parámetro
    app.get("usuario", ":id") { req async throws -> Usuario in
        guard let id = req.parameters.get("id", as: UUID.self) else {
            throw Abort(.badRequest)
        }
        guard let usuario = try await Usuario.find(id, on: req.db) else {
            throw Abort(.notFound)
        }
        return usuario
    }

    // Grupo de rutas con prefijo y middleware
    let api = app.grouped("api", "v1")
        .grouped(TokenAuthMiddleware())
    api.post("articulos", use: ArticuloController().crear)
}

Fluent: ORM para Swift

Vapor incluye Fluent, un ORM que soporta PostgreSQL, MySQL, SQLite y MongoDB. Los modelos son structs o clases conformando el protocolo Model:

import Fluent
import Vapor

final class Articulo: Model, Content {
    static let schema = "articulos"

    @ID(key: .id)
    var id: UUID?

    @Field(key: "titulo")
    var titulo: String

    @Field(key: "contenido")
    var contenido: String

    @Timestamp(key: "created_at", on: .create)
    var createdAt: Date?

    init() {}

    init(id: UUID? = nil, titulo: String, contenido: String) {
        self.id = id
        self.titulo = titulo
        self.contenido = contenido
    }
}

Las migraciones son código Swift tipado:

struct CreateArticulo: AsyncMigration {
    func prepare(on database: Database) async throws {
        try await database.schema("articulos")
            .id()
            .field("titulo", .string, .required)
            .field("contenido", .string, .required)
            .field("created_at", .datetime)
            .create()
    }

    func revert(on database: Database) async throws {
        try await database.schema("articulos").delete()
    }
}

Autenticación con JWT

Vapor tiene soporte integrado para JWT a través del paquete vapor/jwt:

// Generar token
let payload = TokenPayload(
    sub: .init(value: usuario.id!.uuidString),
    exp: .init(value: Date().addingTimeInterval(3600))
)
let token = try req.jwt.sign(payload)

// Verificar token en middleware
struct TokenAuthMiddleware: AsyncMiddleware {
    func respond(to request: Request, chainingTo next: AsyncResponder) async throws -> Response {
        let payload = try request.jwt.verify(as: TokenPayload.self)
        request.auth.login(payload)
        return try await next.respond(to: request)
    }
}

Vapor y Swift 6

Vapor 4 es compatible con Swift 6 y su modo de concurrencia estricta. Las rutas son automáticamente @Sendable, los handlers son funciones async que el compilador verifica. Si vienes de frameworks como Express en Node.js o Gin en Go, el equivalente en Go con goroutines es diferente en filosofía pero similar en ergonomía de routing.

Despliegue

Vapor se despliega como cualquier binario nativo. La forma más común es Docker:

# Dockerfile de ejemplo
FROM swift:5.10-jammy as builder
WORKDIR /app
COPY . .
RUN swift build -c release

FROM ubuntu:jammy
WORKDIR /app
COPY --from=builder /app/.build/release/App .
EXPOSE 8080
CMD ["./App", "serve", "--hostname", "0.0.0.0"]

El binario resultante es pequeño (10-30 MB típicamente) y arranca en milisegundos. No necesita runtime de Node, JVM ni intérprete de Python.

Imagen: Pexels / Digital Buggu

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP