A Swift SDK for Pocketbase v0.32.0.
- âś… Generic user authentication (supports any model)
- âś… User authentication (sign up, sign in, sign out)
- âś… Token refresh
- âś… Password reset
- âś… CRUD operations
- âś… Realtime subscriptions
- âś… Type-safe data models
- âś… Automatic token management (stores tokens securely)
Note: This is a work in progress. The SDK is not yet have 100% feature parity with the js-sdk but it's close. Any contributions are welcome!
Pocketbase is a great framework for quick prototyping and small scale applications. In an ideal world, Pocketbase would generate Swagger/OpenAPI documentation, but currently it doesn't. And there is no plan to add it in the future.
This SDK aims to make it easier to use Pocketbase with Swift projects.
Add the package to your Package.swift:
dependencies: [
.package(url: "https://github.com/drewalth/pocketbase-swift-sdk.git", from: "1.0.0")
],
targets: [
.target(name: "YourApp", dependencies: [.product(name: "PocketBase", package: "pocketbase-swift-sdk")])
]// Add the PocketBase instance to the environment
private struct PB: EnvironmentKey {
static let defaultValue = PocketBase(baseURL: "http://127.0.0.1:8090")
}
extension EnvironmentValues {
var pocketBase: PocketBase {
get {
self[PB.self]
} set {
self[PB.self] = newValue
}
}
}
// Access the PocketBase instance in your views
struct ContentView: View {
@Environment(\.pocketBase) var pocketBase
@State private var posts: [Post] = []
var body: some View {
List(posts, id: \.id) { post in
Text(post.title)
}
.task {
do {
let postCollection: Collection<Post> = pocketBase.collection("posts")
let postResult = try await postCollection.getList()
posts = postResult.items
} catch {
print(error)
}
}
}
}See the example project for a more complete example.
The SDK uses generics to support any user model that conforms to PBIdentifiableCollection. You need to define your own User models:
// Define your User model
struct User: PBIdentifiableCollection {
let id: String
let email: String
let username: String?
let name: String?
let avatar: String?
let verified: Bool
let created: String
let updated: String
let collectionId: String
let collectionName: String
// Add any additional fields your PocketBase user collection has
}The SDK provides comprehensive authentication functionality with generic support:
// Sign up a new user
let createUserDto = CreateUser(
email: "new@drewalth.com",
name: "Test User",
password: "password123",
passwordConfirm: "password123")
let authResult = try await pb.signUp(dto: createUserDto, userType: User.self)
// Sign in with email/username and password
let authResult = try await pb.authWithPassword(
email: "user@example.com",
password: "password123",
userType: User.self
)
// Refresh authentication token
let refreshResult = try await pb.authRefresh(userType: User.self)
// Check authentication status
if pb.isAuthenticated {
print("User is authenticated")
print("User ID: \(pb.currentUserId ?? "Unknown")")
}
// Sign out
pb.signOut()// Request password reset
try await pb.requestPasswordReset(email: "user@example.com")
// Confirm password reset (with token from email)
try await pb.confirmPasswordReset(
token: "reset_token_from_email",
password: "newpassword",
passwordConfirm: "newpassword"
)
// Request email verification
try await pb.requestVerification(email: "user@example.com")
// Confirm email verification (with token from email)
try await pb.confirmVerification(token: "verification_token_from_email")let bookmarksCollection = pb.collection("bookmarks")
// Get a single record
let bookmark = try await bookmarksCollection.getOne(id: "e849z3g13jls740")
// Get a list of records
let bookmarks = try await bookmarksCollection.getList()
// Create a new record
let newBookmark = try await bookmarksCollection.create(record: Bookmark(
title: "My First Bookmark",
url: "https://www.google.com"
))
// Update a record
let updatedBookmark = try await bookmarksCollection.update(
id: newBookmark.id,
record: Bookmark(
title: "My Updated Bookmark",
url: "https://www.google.com"
)
)
// Delete a record
try await bookmarksCollection.delete(id: newBookmark.id)The SDK provides powerful expand functionality to include related data in your queries:
// Expand a single field
let expandQuery = ExpandQuery("author")
let posts = try await pb.getList(
collection: "posts",
model: Post.self,
expand: expandQuery
)
// Expand multiple fields
let expandQuery = ExpandQuery("author", "category", "tags")
let posts = try await pb.getList(
collection: "posts",
model: Post.self,
expand: expandQuery
)// Expand nested relationships
let expandQuery = ExpandQuery("author.profile", "category.parent")
let posts = try await pb.getList(
collection: "posts",
model: Post.self,
expand: expandQuery
)// Use the builder pattern for complex expansions
let expandQuery = ExpandBuilder()
.field("author")
.field("category")
.nested("author.profile")
.nested("category.parent")
.build()
let posts = try await pb.getList(
collection: "posts",
model: Post.self,
expand: expandQuery
)let posts: Collection<Post> = pb.collection("posts")
// Expand with fluent API
let expandQuery = ExpandQuery("author", "category")
let result = try await posts.getList(expand: expandQuery)
// Expand on single record
let post = try await posts.getOne(
id: "post-id",
expand: ExpandQuery("author.profile")
)let builder = ExpandBuilder()
if shouldIncludeAuthor {
builder.field("author")
}
if shouldIncludeCategory {
builder.field("category")
}
let expandQuery = builder.build()
let posts = try await pb.getList(
collection: "posts",
model: Post.self,
expand: expandQuery
)let realtime = pb.realtime(
collection: "bookmarks",
record: "*",
onConnect: {
print("Connected to realtime")
},
onDisconnect: {
print("Disconnected from realtime")
},
onEvent: { event in
print("Received event: \(event.action) for record: \(event.record)")
}
)
try await realtime.subscribe()
// Unsubscribe from realtime
realtime.unsubscribe()Define your data models by conforming to PBCollection:
struct Bookmark: PBCollection {
let id: String
let title: String
let url: String
let created: String
let updated: String
let collectionId: String
let collectionName: String
}For models that need an id property (like User and Admin), use PBIdentifiableCollection:
struct User: PBIdentifiableCollection {
let id: String
let email: String
// ... other properties
}