From 4e55b702840e3a6f9e718d2e86539289e990fb46 Mon Sep 17 00:00:00 2001 From: Nigro Simone Date: Sat, 15 Aug 2026 10:08:39 +0200 Subject: [PATCH] Add vapor framework --- frameworks/vapor/Dockerfile | 17 +++ frameworks/vapor/Package.swift | 16 +++ frameworks/vapor/README.md | 26 +++++ frameworks/vapor/Sources/server/main.swift | 115 +++++++++++++++++++++ frameworks/vapor/meta.json | 19 ++++ 5 files changed, 193 insertions(+) create mode 100644 frameworks/vapor/Dockerfile create mode 100644 frameworks/vapor/Package.swift create mode 100644 frameworks/vapor/README.md create mode 100644 frameworks/vapor/Sources/server/main.swift create mode 100644 frameworks/vapor/meta.json diff --git a/frameworks/vapor/Dockerfile b/frameworks/vapor/Dockerfile new file mode 100644 index 000000000..92107b748 --- /dev/null +++ b/frameworks/vapor/Dockerfile @@ -0,0 +1,17 @@ +FROM swift:6.2-jammy AS build +RUN apt-get update && \ + apt-get install -y --no-install-recommends libssl-dev zlib1g-dev && \ + rm -rf /var/lib/apt/lists/* +WORKDIR /app +COPY Package.swift . +COPY Sources ./Sources +RUN swift build -c release + +FROM ubuntu:22.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends ca-certificates libcurl4 libxml2 zlib1g && \ + rm -rf /var/lib/apt/lists/* +COPY --from=build /usr/lib/swift/linux/lib*.so /usr/lib/swift/linux/ +COPY --from=build /app/.build/release/server /server +EXPOSE 8080 +CMD ["/server"] diff --git a/frameworks/vapor/Package.swift b/frameworks/vapor/Package.swift new file mode 100644 index 000000000..2eb227bb5 --- /dev/null +++ b/frameworks/vapor/Package.swift @@ -0,0 +1,16 @@ +// swift-tools-version:5.9 +import PackageDescription + +let package = Package( + name: "server", + platforms: [.macOS(.v13)], + dependencies: [ + .package(url: "https://github.com/vapor/vapor.git", from: "4.122.0") + ], + targets: [ + .executableTarget( + name: "server", + dependencies: [.product(name: "Vapor", package: "vapor")] + ) + ] +) diff --git a/frameworks/vapor/README.md b/frameworks/vapor/README.md new file mode 100644 index 000000000..455b280e3 --- /dev/null +++ b/frameworks/vapor/README.md @@ -0,0 +1,26 @@ +# vapor + +Vapor 4 on SwiftNIO, default configuration. + +## Stack + +- **Language:** Swift 6.2 +- **Framework:** Vapor 4.122 +- **Build:** Multi-stage, `ubuntu:22.04` runtime + +## Endpoints + +| Endpoint | Method | Description | +|----------|--------|-------------| +| `/pipeline` | GET | Returns `ok` (plain text) | +| `/baseline11` | GET | Sums query parameter values | +| `/baseline11` | POST | Sums query parameters + request body | +| `/json/{count}?m=N` | GET | First `count` dataset items with `total = price * quantity * m` | +| `/upload` | POST | Streams the body and returns the byte count | + +## Notes + +- Routing and path/query decoding through the Vapor API +- JSON through `Content`, encoded per request by Codable +- Compression through `http.server.configuration.responseCompression` +- `/upload` uses a streaming body so the 20 MB body is never collected diff --git a/frameworks/vapor/Sources/server/main.swift b/frameworks/vapor/Sources/server/main.swift new file mode 100644 index 000000000..47283cecb --- /dev/null +++ b/frameworks/vapor/Sources/server/main.swift @@ -0,0 +1,115 @@ +import Foundation +import Vapor + +struct Rating: Content { + let score: Int + let count: Int +} + +struct DatasetItem: Content { + let id: Int + let name: String + let category: String + let price: Int + let quantity: Int + let active: Bool + let tags: [String] + let rating: Rating +} + +struct ProcessedItem: Content { + let id: Int + let name: String + let category: String + let price: Int + let quantity: Int + let active: Bool + let tags: [String] + let rating: Rating + let total: Int +} + +struct ProcessResponse: Content { + let items: [ProcessedItem] + let count: Int +} + +let datasetPath = Environment.get("DATASET_PATH") ?? "/data/dataset.json" +let dataset: [DatasetItem] = { + guard let data = FileManager.default.contents(atPath: datasetPath), + let items = try? JSONDecoder().decode([DatasetItem].self, from: data) + else { + return [] + } + return items +}() + +func plain(_ body: String) -> Response { + Response(status: .ok, headers: ["content-type": "text/plain"], body: .init(string: body)) +} + +func querySum(_ request: Request) -> Int { + guard let query = request.url.query else { return 0 } + var sum = 0 + for pair in query.split(separator: "&") { + let parts = pair.split(separator: "=", maxSplits: 1) + if parts.count == 2, let value = Int(parts[1]) { + sum += value + } + } + return sum +} + +let app = try await Application.make(.production) +app.logger.logLevel = .error +app.http.server.configuration.hostname = "0.0.0.0" +app.http.server.configuration.port = 8080 +app.http.server.configuration.responseCompression = .enabled + +app.get("pipeline") { _ in plain("ok") } + +app.on(.GET, "baseline11") { request in + plain(String(querySum(request))) +} + +app.on(.POST, "baseline11", body: .collect(maxSize: "1mb")) { request -> Response in + var sum = querySum(request) + if let buffer = request.body.data, + let text = buffer.getString(at: buffer.readerIndex, length: buffer.readableBytes), + let value = Int(text.trimmingCharacters(in: .whitespacesAndNewlines)) { + sum += value + } + return plain(String(sum)) +} + +app.get("json", ":count") { request -> ProcessResponse in + let requested = request.parameters.get("count", as: Int.self) ?? 0 + let count = max(0, min(requested, dataset.count)) + let m = (try? request.query.get(Int.self, at: "m")) ?? 1 + + let items = dataset.prefix(count).map { item in + ProcessedItem( + id: item.id, + name: item.name, + category: item.category, + price: item.price, + quantity: item.quantity, + active: item.active, + tags: item.tags, + rating: item.rating, + total: item.price * item.quantity * m + ) + } + return ProcessResponse(items: items, count: items.count) +} + +app.on(.POST, "upload", body: .stream) { request -> Response in + var size = 0 + for try await chunk in request.body { + size += chunk.readableBytes + } + return plain(String(size)) +} + +try await app.execute() +try await app.asyncShutdown() diff --git a/frameworks/vapor/meta.json b/frameworks/vapor/meta.json new file mode 100644 index 000000000..c65ce7a91 --- /dev/null +++ b/frameworks/vapor/meta.json @@ -0,0 +1,19 @@ +{ + "display_name": "vapor", + "language": "Swift", + "type": "flagship", + "mode": "standard", + "engine": "SwiftNIO", + "description": "Vapor 4 on SwiftNIO, default configuration. Routing and parameter decoding through the Vapor API, Codable JSON responses, gzip through the server response compression setting.", + "repo": "https://github.com/vapor/vapor", + "enabled": true, + "tests": [ + "baseline", + "pipelined", + "limited-conn", + "json", + "json-comp", + "upload" + ], + "maintainers": [] +}