REST API Backend
The REST API backend allows iOS and macOS apps to connect to a remote SwiftDataServer instance. Use the same SwiftData API you know on the client, with your server handling persistence.
Installation
Add the REST backend to your target:
.product(name: "RESTBackend", package: "SwiftDataServer")
Configuration
import SwiftDataServer
import RESTBackend
let backend = RESTBackend(
baseURL: URL(string: "https://api.example.com")!,
accessToken: "your-access-token"
)
let container = try ModelContainer(for: User.self, Post.self)
try await container.connect(to: backend)
Authentication
Configure authentication headers for your API:
// Bearer token authentication
let backend = RESTBackend(
baseURL: URL(string: "https://api.example.com")!,
accessToken: "your-jwt-token"
)
// Custom headers
let backend = RESTBackend(
baseURL: URL(string: "https://api.example.com")!,
headers: [
"Authorization": "Bearer \(token)",
"X-API-Key": "your-api-key"
]
)
Usage
Once configured, use the standard SwiftData APIs:
let context = container.mainContext()
// Fetch all users
let users = try await context.fetchAsync(FetchDescriptor<User>())
// Create a new user
let user = User(name: "Alice", email: "alice@example.com")
context.insert(user)
try await context.saveAsync()
// Query with predicates
let predicate = #Predicate<User> { $0.age > 18 }
let adults = try await context.fetchAsync(
FetchDescriptor<User>(predicate: predicate)
)
Server Setup
Your server needs to expose the SwiftDataServer REST API. With Vapor:
import Vapor
import SwiftDataServer
import VaporIntegration
func configure(_ app: Application) async throws {
// ... database setup ...
// Register REST API routes
try app.swiftData.registerRESTRoutes()
}
This exposes endpoints for all registered models at /api/v1/{model}.
Offline Support
Enable local caching for offline access:
let backend = RESTBackend(
baseURL: URL(string: "https://api.example.com")!,
accessToken: "your-token",
cachePolicy: .cacheFirst, // Use cache when offline
cacheDuration: 3600 // 1 hour
)
Error Handling
do {
let users = try await context.fetchAsync(FetchDescriptor<User>())
} catch let error as RESTBackendError {
switch error {
case .networkError(let underlying):
print("Network error: \(underlying)")
case .unauthorized:
print("Invalid or expired token")
case .serverError(let status, let message):
print("Server error \(status): \(message)")
}
}
Requirements
- iOS 17+ / macOS 14+
- A SwiftDataServer instance with REST routes enabled
- Network connectivity (or cached data with offline support)
Next Steps
- Vapor Integration - Set up the server-side API
- Predicates - Build complex queries
- Defining Models - Share models between client and server