Introduction to Working with Databases in Swift
Swift has long ceased to be a language exclusively for mobile development. With the advent of server frameworks such as Vapor and Kitura, Swift has become a full-fledged tool for creating backend solutions. A key aspect of any server system is working with databases. In this article, we will look at how to connect and interact with two popular DBMS: relational PostgreSQL and document-oriented MongoDB. You will learn which libraries to use, how to configure a connection, and perform basic CRUD operations in pure Swift.
PostgreSQL in Swift: Setup and Basic Operations
PostgreSQL is one of the most reliable relational databases. There are several libraries for working with it in Swift, but the most popular is PostgresNIO — an asynchronous driver built on top of SwiftNIO. If you are using the Vapor framework, working with PostgreSQL is simplified through the Fluent ORM.
Connecting to PostgreSQL via PostgresNIO
Let's start by adding the dependency. In Package.swift, add:
// swift-tools-version:5.7import PackageDescription
let package = Package( name: "MyApp", dependencies: [ .package(url: "https://github.com/vapor/postgres-nio.git", from: "1.18.0") ], targets: [ .target(name: "MyApp", dependencies: [ .product(name: "PostgresNIO", package: "postgres-nio") ]) ])Example of connecting and executing a simple SELECT query:
import PostgresNIOimport NIOCoreimport NIOPosix
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let config = PostgresConnection.Configuration( host: "localhost", port: 5432, username: "myuser", password: "mypassword", database: "mydb", tls: .disable)
let connection = try await PostgresConnection.connect( on: eventLoopGroup.next(), configuration: config)
let rows = try await connection.query("SELECT id, name FROM users LIMIT 5;", logger: nil)
for try await row in rows { let id: Int = try row["id"].decode(Int.self) let name: String = try row["name"].decode(String.self) print("User: \\(id) - \\(name)")}Working with Vapor Fluent (ORM)
Fluent provides a high-level API for working with PostgreSQL. A user model would look like this:
import Fluentimport 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 }}
// Creating a recordlet user = User(name: "Ivan", email: "ivan@example.com")try await user.save(on: req.db)
// Querying all userslet users = try await User.query(on: req.db).all()MongoDB in Swift: Working with Documents
MongoDB is a NoSQL database that stores data in BSON (binary JSON) format. For Swift, there is an official driver MongoSwift, developed by MongoDB Inc. It supports asynchronous operations and synchronous mode.
Installing and Connecting MongoSwift
Add the dependency to Package.swift:
dependencies: [ .package(url: "https://github.com/mongodb/mongo-swift-driver.git", from: "1.3.0")],targets: [ .target(name: "MyApp", dependencies: [ .product(name: "MongoSwift", package: "mongo-swift-driver") ])]Example of connecting to a local MongoDB and inserting a document:
import MongoSwift
let client = try MongoClient("mongodb://localhost:27017")let db = client.db("mydatabase")let collection = db.collection("u