Introduction : Pourquoi Swift est une plateforme mature pour les microservices
Traditionnellement, Swift est associé au développement iOS et macOS. Cependant, avec l'émergence des frameworks Vapor et Hummingbird, ainsi que de la bibliothèque SwiftNIO, Swift est devenu un langage à part entière pour le développement côté serveur. L'architecture de microservices en Swift n'est pas seulement une tendance, mais un choix pragmatique pour les projets où la performance, la sécurité des types et l'intégration native avec l'écosystème Apple sont importantes.
Dans cet article, nous aborderons les aspects avancés de la construction de microservices en Swift : du choix du transport au déploiement dans Docker. Les exemples de code sont destinés à Swift 5.9+ et macOS/Linux.
Architecture d'un microservice en Swift : du monolithe au système distribué
Choix du framework : Vapor vs Hummingbird
Pour les solutions de production, Vapor 4 (stable, large communauté) ou Hummingbird (léger, minimaliste) sont recommandés. Les deux sont construits sur SwiftNIO.
La structure de base d'un microservice sur Vapor comprend :
- Routes (itinéraires) — traitement des requêtes HTTP.
- Controllers (contrôleurs) — logique métier.
- Services (services) — modules isolés (base de données, API externes).
- Models (modèles) — Fluent ORM pour travailler avec la base de données.
// Exemple de structure de base d'un microservice sur 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) }}Protocoles et Injection de Dépendances
Pour un couplage faible, utilisez des protocoles. Cela simplifie les tests et le remplacement des composants.
protocol PaymentServiceProtocol { func processPayment(amount: Double, currency: String) async throws -> PaymentResult}
final class StripeService: PaymentServiceProtocol { func processPayment(amount: Double, currency: String) async throws -> PaymentResult { // Logique d'appel à l'API Stripe }}
// Enregistrement dans le conteneur DI de Vaporapp.services.register(PaymentServiceProtocol.self) { _ in StripeService() }Communication avancée : gRPC et Async/Await
Pourquoi gRPC plutôt que REST
Pour les microservices internes, gRPC est préférable à REST en raison de :
- Typage strict via Protocol Buffers.
- Protocole binaire (moins de trafic).
- Support intégré du streaming.
Swift prend en charge gRPC via la bibliothèque grpc-swift. Exemple de définition de service :
// 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;}Génération du code Swift :
protoc --swift_out=. --grpc-swift_out=. user.protoImplémentation du serveur 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 dans les microservices
Swift 5.5+ a apporté