Swift Server Side: MongoDB Mini-Tutorial 2

11-Dez-2020

mongodb, swift

I just wanted to add a quick update to my previous mini tutorial https://david.dev/Server-side-swift-kitura-mongo-db-tutorial (wow! amost a year) on using MongoDB with a SWIFT server side framework like Kitura or Vapor.
First, the official MongoDB Swift driver https://github.com/mongodb/mongo-swift-driver is now at 1.0.1 and no longer requires the C library to be installed. This is excellent news.


Secondly, the API now has both Async and Synchronous options.


Installation and other matters are already covered in the readme of the driver so I will focus in the unwritten rules on how to sort or filter the collection.find that are essential even in a small blog/CMS:


Let's assume we start with a struct for our blog posts:


struct Pages: Codable {
var title: String
var slug: String
var body: String
var date: String
}

Now we create a route in Kitura to display our index. Like in every CMS or blog we need to be able to limit the results, sort them (by ID or date) and may be even filter them. To do that you need to create 2 constants and the pass it to the collection.find:


router.get("/", handler: {
request , response,next in
let sort: BSONDocument = ["_id": -1]
// sorting with options
let options = FindOptions(limit: 30, sort: sort)
// filters let query: BSONDocument = [ "draft": [ "$ne": "true" ] ]
let documents = try collection.find(options: options)
// if we want to use filters it would be
let documents = try collection.find(query, options: options)
var pages: [[String: String]] = []
for d in documents {
let value = try d.get() pages.append(["title": value.title, "slug": value.slug, "body": value.body, "date": value.date])
print(value)
}
try response.render("index.stencil", with: ["Pages": pages]) response.status(.OK)
})

so here we have it! we can now sort our articles by id (or date) we can limit the number of results and also filter for example all articles that don't have "draft" set as true ($ne non equal).


if you want to find a single document you can use this format (assuming name is the parameter that you want to find e.g. the slug of a page or blog article):


router.get("/:name") { request, response, next
in guard let name = request.parameters["name"]
else {
_ = response.send(status: .badRequest)
return next()
}
let query: BSONDocument = ["slug": .string(name)]
let documents = try collection.find(query)
var page: [String: String] = [:]
for d in documents {
let value = try d.get()
print(value)
page = [
"title": value.title,
"slug": value.slug,
"body": value.body,
"date": value.date,
]
break
}
if page.isEmpty {
// response.send ("<h1>&#127934; not found </h1>")
let title = ["title": "Page not Found - 404 "]
try response.render("404.stencil", context: title)
next()
} else {
try response.render("page.stencil", with: page)
response.status(.OK)
}
}

fetching one article is obviously more straightforward. The real missing bit from the documentation/readme is an example with sort and filters that is essential.


I think it is great that MongoDB invested the time to create, improve and maintain a SWIFT driver. Since I am not proficient at all in Swift I find it interesting but for server side I think NodeJS provides a faster development cycle and a more straightforward API.


This said I am sure that for some Swift developers this is great news. I recently bought a book about SWIFT server side with Vapor 4 (that seems the most active of the two Swift server side frameworks) so I might have a deeper look. I remain fascinated but I enjoy NodeJS more.


In Kitura the existing template engine (stencil) is fairly basic (there is not even a way to escape HTML in the rendering which is pretty annoying) and other small bits are not as encouraging for me. Even SwiftUI seems to be way more intuitive!


Back to home

👏