الخدمات المصغرة بلغة Swift: الهندسة والتطبيق لنظامي iOS/macOS

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة
```html

مقدمة: لماذا Swift للخدمات المصغرة؟

تقليديًا، يرتبط Swift بتطوير iOS وmacOS، ولكن مع ظهور أطر الخادم مثل Vapor وKitura، أصبحت اللغة أداة قوية لبناء بنية الخدمات المصغرة. تتيح الخدمات المصغرة باستخدام Swift استخدام لغة واحدة على كل من العميل والخادم، مما يبسط صيانة قاعدة الشيفرة ويسرع التطوير. في هذه المقالة، سنحلل المبادئ الأساسية لبناء الخدمات المصغرة باستخدام Swift، ونستعرض أمثلة عملية مع Vapor وCombine وgRPC، بالإضافة إلى مناقشة قضايا النشر.

الجزء الرئيسي

1. بنية الخدمات المصغرة في Swift: المبادئ الأساسية

تفترض بنية الخدمات المصغرة تقسيم التطبيق إلى خدمات صغيرة مترابطة بشكل ضعيف. كل خدمة مسؤولة عن منطق أعمالها الخاص ويمكن تطويرها ونشرها وتوسيع نطاقها بشكل مستقل. بالنسبة لـ Swift، هذا يعني:

  • التقسيم حسب المجالات (DDD): كل خدمة مصغرة تمثل سياقًا محددًا منفصلاً.
  • قواعد بيانات مستقلة: تستخدم كل خدمة قاعدة البيانات الخاصة بها (PostgreSQL، SQLite، Redis).
  • التواصل الموجه بالأحداث: عبر قوائم الانتظار (RabbitMQ، Kafka) أو HTTP/gRPC.

مثال على هيكل المشروع الأساسي في Vapor:

// هيكل مجلدات الخدمة المصغرة "UserService"
UserService/
├── Sources/
│   ├── App/
│   │   ├── Controllers/
│   │   ├── Models/
│   │   ├── Migrations/
│   │   └── configure.swift
├── Tests/
├── Package.swift
└── Dockerfile

يجب أن تحتوي كل خدمة مصغرة على Package.swift الخاص بها ونقطة الدخول main.swift.

2. إنشاء خدمة مصغرة في Vapor مع REST API

Vapor هو إطار الخادم الأكثر شيوعًا لـ Swift. لنفكر في إنشاء خدمة مصغرة بسيطة لإدارة المستخدمين.

2.1 إعداد المشروع

قم بتثبيت Vapor Toolbox وأنشئ مشروعًا جديدًا:

brew install vapor
vapor new UserService --template=api

2.2 النموذج ووحدة التحكم

لنحدد النموذج User باستخدام Fluent ORM:

import Fluent
import Vapor

final class User: Model, Content {
    static let schema = "users"
    
    @ID(key: .id)
    var id: UUID?
    
    @Field(key: "name")
    var name: String
    
    @Field(key: "email")
    var email: String
    
    init() { }
    
    init(id: UUID? = nil, name: String, email: String) {
        self.id = id
        self.name = name
        self.email = email
    }
}

لننشئ وحدة تحكم بعمليات CRUD:

struct UserController: RouteCollection {
    func boot(routes: RoutesBuilder) throws {
        let users = routes.grouped("users")
        users.get(use: index)
        users.post(use: create)
        users.group(":userID") { user in
            user.get(use: show)
            user.put(use: update)
            user.delete(use: delete)
        }
    }
    
    // GET /users
    func index(req: Request) async throws -> [User] {
        try await User.query(on: req.db).all()
    }
    
    // POST /users
    func create(req: Request) async throws -> User {
        let user = try req.content.decode(User.self)
        try await user.save(on: req.db)
        return user
    }
    
    // GET /users/:id
    func show(req: Request) async throws -> User {
        guard let user = try await User.find(req.parameters.get("userID"), on: req.db) else {
            throw Abort(.notFound)
        }
        return user
    }
    
    // PUT /users/:id
    func update(req: Request) async throws -> User {
        guard let user = try await User.find(req.parameters.get("userID"), on: req.db) else {
            throw Abort(.notFound)
        }
        let updated = try req.content.decode(User.self)
        user.name = updated.name
        user.email = updated.email
        try await
```                

المدونات

توصيات الكتب