I'd like to leave a few tips that I think are adamant in writing good APIs. I've come across all of these mistakes, and they are a pain to deal with. Some more than others, but all decrease the enjoyability of working with them.
Back when the blog was written in Ruby, I wrote that I eventually went ahead and implemented an RSS feed, and that it was much easier than expected. Turns out I didn't even need a library to do it, it's only a matter of creating an XML document.
The first post in the Server Side Swift series will be about initializing the project, its structure, and configuring your Droplet. Running the vapor xcode -y command (although I always run swift build first) will download dependencies, build them, configure an Xcode project, and you will end up with a structure like this:
I finally decided to migrate the blog from Node.js to Swift, and that's what I've been working on for the past weeks. It's been fun, and in the upcoming posts I will be writing about how it went. I will prefix them with [SSS], just like I did with [NJS]. The repo can be found here.
Hope you'll enjoy them as much as I did!
Say we have some HTML content we want to display in a UITextView:
if let stringData = string.data(using: .utf16),
let attributedString = try? NSAttributedString(
data: stringData,
options: [.documentType: NSAttributedString.DocumentType.html],
documentAttributes: nil) {
attributedText = attributedString
}
else {
attributedText = nil
}I used to name them by the type of the parameters passed in, for example:
let dictionary = ["name": "Sneakers", "price": "40"]
let product = Product(dictionary: dictionary)
let viewModel = ProductViewModel(product: product)But lately, I've been using a more Swifty approach, by having an external name of from or with:
let dictionary = ["name": "Sneakers", "price": "40"]
let product = Product(from: dictionary)
let viewModel = ProductViewModel(with: product)How do I pick between the two? I go with the following approach:
Sitemaps are used by search engines to know what pages to crawl; they're basically a list of all the URLs available on a website. Last time we saw how to manually create an RSS feed by manually creating an XML document, and a sitemap is also just an XML document.
First, let's add the route to our droplet:
func addRoutes() -> Droplet {
get("/sitemap.xml", handler: SitemapController.create)
// [...]
}As we saw in the previous post, we need a controller that has a method with the same signature as the handler:
struct SitemapController {
static func create(with request: Request) throws -> ResponseRepresentable {This is a bit tricky, since my routes for posts and pages are the same, and I differentiate between the two if I can create an Int out of the lastPathComponent. I know it's not the best approach, but since URLs should be permanent, I never moved to a /page/x structure. I also kind of dislike that structure ¯\_(ツ)_/¯.
In the first post in this series, I briefly presented the Droplet extension, with a very basic addRoutes method, just to present the methods in the extension itself. Let's give it a few routes:
extension Droplet {Let's start by defining our Post model:
struct Post {break is used to exit the current scope, for example a for loop:
for i in 1...10 {
guard i < 9 else { break }
// Code here.
}But what if we have nested loops, and we want to break a specific one? Swift has us covered, with labels:
outer: for i in 1...10 {
inner: for j in 1...10 {
guard i < 9 else { break outer }
guard j < 8 else { break inner }
// Code here.
}
}But today I found something interesting: you can label if blocks, as well:
// Works with non optional binding ifs as well.
abCheck: if let a = b() {
guard a.condition else { break abCheck }
// Code here.
}