What building a server application in Swift looks like
Server applications are modeled as Swift packages, here’s a simple manifest file:
// swift-tools-version: 5.7
import PackageDescription
let package = Package(
name: "MyServer",
platforms: [.macOS("12.0")],
products: [
.executable(name: "MyServer", targets: ["MyServer"]),
],
dependencies: [
// 👇🏻 Web framework, helps us structure our code and provides basic utilities like routing
.package(url: "https://github.com/vapor/vapor.git", .upToNextMajor(from: "4.0.0")),
],
targets: [
// 👇🏻 This executable target maps the server application entry point
.executableTarget(
name: "MyServer",
dependencies: [
.product(name: "Vapor", package: "vapor")
]
),
.testTarget(
name: "MyServerTests",
dependencies: ["MyServer"]),
]
)Here’s what our framework entry point might look like:
import Vapor
@main
public struct MyServer {
public static func main() async throws {
let webapp = Application()
// 👇🏻 our server endpoints
webapp.get("greet", use: Self.greet)
webapp.post("echo", use: Self.echo)
// 👇🏻 server bootstrap code (provided by Vapor) 🚀
try webapp.run()
}
static func greet(request: Request) async throws -> String {
return "Hello from Swift Server"
}
static func echo(request: Request) async throws -> String {
if let body = request.body.string {
return body
}
return ""
}
}To run this server in our local machine via Xcode, we can:
select the MyServer scheme (generated for us by Xcode)
select the My Mac as the destination
hit run
Once the application has launched, we can use Xcode console to examine log messages emitted by the server. In the logs we can also see at which ip/port the server is listening (typically 127.0.0.1:8080)
For this demo code you can test it via terminal
curl http://127.0.0.1:8080/greet; echo
curl http://127.0.0.1:8080/echo --data "Hello from WWDC 2022"; echoApp side (Client side)
To communicate with the server we just created, we can use code similar to:
import Foundation
struct MyServerClient {
let baseURL = URL(string: "http://127.0.0.1:8080")!
func greet() async throws -> String {
let url = baseURL.appendingPathComponent("greet")
let (data, _) = try await URLSession.shared.data(for: URLRequest(url: url))
guard let responseBody = String(data: data, encoding: .utf8) else {
throw Errors.invalidResponseEncoding
}
return responseBody
}
enum Errors: Error {
case invalidResponseEncoding
}
}Deploying our server to the cloud
There are many cloud providers to choose from: AWS, Google Cloud, Azure, Heroku, and many others
most services offer a git push to deploy system
to make it possible to just
git pushto deploy, cloud services use technologies like buildpacks to compile the application remotely and then deploy the binary artifacts to an ephemeral host
Storage options
Strategies:
files for static data
good if application data is static or changes very slowly and manually
iCloud
for user-centric data or global datasets (no need dedicated server)
databases

