A lightweight HTTP server library for Swift. Built with modern Swift concurrency, it lets you spin up a web server with minimal fuss.
- Swift 6.0 or later
- macOS 14+ or iOS 17+
- HTTP Server - Built on Network framework, handles incoming connections efficiently with async/await
- Routing - Clean API for defining routes with wildcard and parameter matching
- Middleware - Process requests and responses the way you need
- Error Handling - Proper HTTP status codes and error types out of the box
Add to your Package.swift:
let package = Package(
name: "YourApp",
platforms: [.macOS(.v14), .iOS(.v17)],
products: [
.library(
name: "YourApp",
targets: ["YourApp"]
),
],
dependencies: [
.package(url: "https://github.com/taka-2120/SwiftHost.git", .upToNextMajor(from: "1.0.0")), // << Add this!
•••
],
targets: [
.target(
name: "YourApp",
dependencies: [
.product(name: "SwiftHost", package: "SwiftHost"), // << Add this!
•••
],
),
]
)import SwiftHost
let router = Router {
Route(method: .get, path: "/") { _ in
HTTPResponse.text("Hello, World!")
}
Route(method: .post, path: "/users/:id") { request in
let userID = request.pathParameters["id"]
return HTTPResponse.json(["userID": userID])
}
}
let server = HTTPServer(port: 3000, router: router)
try server.start()You can manually set the host/IP address:
// Bind to localhost only
let server = HTTPServer(host: "localhost", port: 3000, router: router)
// Bind to a specific IP
let server = HTTPServer(host: "192.168.1.100", port: 3000, router: router)
// Auto-detect (default)
let server = HTTPServer(port: 3000, router: router)Routes match on HTTP method and path. Paths support parameters and wildcards:
Route(method: .get, path: "/users/:id") { request in
// Access path params
let id = request.pathParameters["id"]
return HTTPResponse.text("User: \(id)")
}
Route(method: .get, path: "/static/*") { request in
// Wildcard matches /static/anything
return HTTPResponse.text("Static file")
}Add middleware to process requests and responses globally:
let router = Router {
Route(method: .get, path: "/") { _ in
HTTPResponse.text("Hello!")
}
}
let server = HTTPServer(port: 3000, router: router)
// Add middleware
server.use(LoggingMiddleware())
server.use(CORSMiddleware())Write your own:
struct AuthMiddleware: Middleware {
func processRequest(_ request: HTTPRequest) async -> HTTPRequest {
// Check auth header, modify request
return request
}
func processResponse(_ response: HTTPResponse) async -> HTTPResponse {
// Modify response if needed
return response
}
}HTTPResponse.text("Hello", statusCode: .ok)
HTTPResponse.json(["key": "value"])
HTTPResponse.html("<h1>Hello</h1>")
HTTPResponse.empty(statusCode: .noContent)Monitor server state:
let server = HTTPServer(
port: 3000,
router: router,
onChangeServerStatus: { state in
print("Server state: \(state)")
},
onConnected: {
print("Client connected")
},
onDisconnected: {
print("Client disconnected")
}
)SwiftHost includes built-in WebSocket support for real-time communication with web pages.
Create a WebSocket server with connection callbacks:
let webSocketServer = WebSocketServer(
onConnected: { clientID in
print("WebSocket client connected: \(clientID)")
},
onDisconnected: { clientID in
print("WebSocket client disconnected: \(clientID)")
},
onMessage: { clientID, message in
print("Message from \(clientID): \(message)")
}
)Pass the WebSocket server to your HTTP server:
let router = Router {
Route(method: .get, path: "/") { _ in
HTTPResponse.html("""
<script>
const ws = new WebSocket('ws://' + location.host);
ws.onmessage = (event) => {
if (event.data === 'refresh') {
location.reload();
}
};
</script>
""")
}
}
let server = HTTPServer(
port: 3000,
router: router,
webSocketServer: webSocketServer
)Refresh all connected pages:
await webSocketServer.refreshPage()Refresh a specific page:
await webSocketServer.refreshPage(clientID)Send a message to all clients:
await webSocketServer.broadcast("Hello, clients!")Send to a specific client:
await webSocketServer.sendText("Hello!", to: clientID)Get connection count:
let count = await webSocketServer.getConnectionCount()Get all connection IDs:
let ids = await webSocketServer.getConnectionIDs()Close a specific connection:
await webSocketServer.closeConnection(clientID)Yu Takahashi