Introducción: Por qué Swift es una plataforma madura para microservicios
Tradicionalmente, Swift se asocia con el desarrollo para iOS y macOS. Sin embargo, con la aparición de los frameworks Vapor y Hummingbird, así como la biblioteca SwiftNIO, Swift se ha convertido en un lenguaje completo para el desarrollo del lado del servidor. La arquitectura de microservicios en Swift no es solo una tendencia, sino una elección pragmática para proyectos donde el rendimiento, la seguridad de tipos y la integración nativa con el ecosistema de Apple son importantes.
En este artículo, exploraremos aspectos avanzados de la construcción de microservicios en Swift: desde la elección del transporte hasta el despliegue en Docker. Los ejemplos de código están orientados a Swift 5.9+ y macOS/Linux.
Arquitectura de microservicio en Swift: del monolito al sistema distribuido
Elección del framework: Vapor vs Hummingbird
Para soluciones de producción, se recomienda Vapor 4 (estable, amplia comunidad) o Hummingbird (ligero, minimalista). Ambos están construidos sobre SwiftNIO.
La estructura básica de un microservicio en Vapor incluye:
- Routes (rutas) — manejo de solicitudes HTTP.
- Controllers (controladores) — lógica de negocio.
- Services (servicios) — módulos aislados (base de datos, APIs externas).
- Models (modelos) — Fluent ORM para trabajar con la BD.
// Ejemplo de estructura básica de microservicio en Vaporimport Vapor
func routes(_ app: Application) throws { let orderController = OrderController() app.get("orders", ":id", use: orderController.getOrder) app.post("orders", use: orderController.createOrder)}
final class OrderController { func getOrder(req: Request) async throws -> Order { let orderID = try req.parameters.require("id", as: UUID.self) return try await Order.find(orderID, on: req.db) ?? Abort(.notFound) }}Protocolos e Inyección de Dependencias
Para un bajo acoplamiento, use protocolos. Esto simplifica las pruebas y el reemplazo de componentes.
protocol PaymentServiceProtocol { func processPayment(amount: Double, currency: String) async throws -> PaymentResult}
final class StripeService: PaymentServiceProtocol { func processPayment(amount: Double, currency: String) async throws -> PaymentResult { // Lógica para llamar a la API de Stripe }}
// Registro en el contenedor DI de Vaporapp.services.register(PaymentServiceProtocol.self) { _ in StripeService() }Comunicación avanzada: gRPC y Async/Await
Por qué gRPC en lugar de REST
Para microservicios internos, gRPC es preferible a REST debido a:
- Tipado estricto mediante Protocol Buffers.
- Protocolo binario (menos tráfico).
- Soporte integrado para streaming.
Swift admite gRPC a través de la biblioteca grpc-swift. Ejemplo de definición de servicio:
// user.protoservice UserService { rpc GetUser (UserRequest) returns (UserResponse); rpc ListUsers (Empty) returns (stream UserResponse);}
message UserRequest { string user_id = 1;}
message UserResponse { string id = 1; string name = 2; string email = 3;}Generación de código Swift:
protoc --swift_out=. --grpc-swift_out=. user.protoImplementación del servidor en Swift:
import GRPCimport NIO
final class UserServiceImpl: UserServiceProvider { func getuser(request: UserRequest, context: StatusOnlyCallContext) -> EventLoopFuture { let user = UserResponse.with { $0.id = request.userID $0.name = "John Doe" $0.email = "john@example.com" } return context.eventLoop.makeSucceededFuture(user) }} Async/Await en microservicios
Swift 5.5+ introdujo