Skip to content

Commit 8a688ad

Browse files
committed
Initial version of swift generator
1 parent cea1870 commit 8a688ad

29 files changed

+1587
-1
lines changed

.gitignore

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
5+
xcuserdata/
6+
DerivedData/
7+
.netrc
8+
.build
9+
.swiftpm
10+
Package.resolved
11+
client.swift
12+
node_modules

LICENCE.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2019-present https://github.com/webrpc authors
2+
3+
MIT License
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
the Software, and to permit persons to whom the Software is furnished to do so,
10+
subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+45-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,45 @@
1-
# gen-swift
1+
# gen-swift
2+
3+
This repo contains the templates used by the `webrpc-gen` cli to code-generate
4+
webrpc Swift client code.
5+
6+
This generator, from a webrpc schema/design file will code-generate:
7+
8+
1. Client -- a Swift client to speak to a webrpc server using the
9+
provided schema. This client is compatible with any webrpc server language (ie. Go, nodejs, etc.).
10+
11+
## Dependencies
12+
13+
In order to support `any` type in webrpc, we use [AnyCodable](https://github.com/Flight-School/AnyCodable).
14+
This is a dependency of the generated code, so you must add it to your project.
15+
16+
## Usage
17+
18+
```
19+
webrpc-gen -schema=example.ridl -target=swift -server -client -out=./example.gen.swift
20+
```
21+
22+
or
23+
24+
```
25+
webrpc-gen -schema=example.ridl -target=github.com/webrpc/[email protected] -server -client -out=./example.get.swift
26+
```
27+
28+
or
29+
30+
```
31+
webrpc-gen -schema=example.ridl -target=./local-templates-on-disk -server -client -out=./example.gen.swift
32+
```
33+
34+
As you can see, the `-target` supports default `swift`, any git URI, or a local folder :)
35+
36+
### Set custom template variables
37+
Change any of the following values by passing `-option="Value"` CLI flag to `webrpc-gen`.
38+
39+
| webrpc-gen -option | Description | Default value |
40+
|----------------------|----------------------------|----------------------------|
41+
| `-client` | generate client code | unset (`false`) |
42+
43+
## LICENSE
44+
45+
[MIT LICENSE](./LICENSE)

Tests/Package.swift

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// swift-tools-version: 5.8
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "gen-swift",
8+
platforms: [.macOS(.v13), .iOS(.v15)],
9+
products: [
10+
// Products define the executables and libraries a package produces, making them visible to other packages.
11+
.library(
12+
name: "gen-swift",
13+
targets: ["gen-swift"]),
14+
15+
],
16+
dependencies: [.package(url: "https://github.com/Flight-School/AnyCodable", from: "0.6.7")],
17+
targets: [
18+
// Targets are the basic building blocks of a package, defining a module or a test suite.
19+
// Targets can depend on other targets in this package and products from dependencies.
20+
.target(
21+
name: "gen-swift",
22+
dependencies: ["AnyCodable"]),
23+
.testTarget(
24+
name: "gen-swiftTests",
25+
dependencies: ["gen-swift"]),
26+
]
27+
)
+236
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
import XCTest
2+
@testable import gen_swift
3+
4+
final class gen_swiftTests: XCTestCase {
5+
6+
private let client = TestApiClient(hostname: "http://localhost:9988")
7+
8+
func testEmpty() async throws {
9+
await XCTAssertNoThrow(try await client.getEmpty(), "getEmpty() should get empty type successfully")
10+
}
11+
12+
func testError() async throws {
13+
await XCTAssertThrowsError(try await client.getError(), "getError() should throw error")
14+
}
15+
16+
func testOne() async throws {
17+
let response = try await client.getOne()
18+
await XCTAssertNoThrow(try await client.sendOne(one: response),
19+
"getOne() should receive simple type and send it back via sendOne() successfully")
20+
21+
}
22+
23+
func testMulti() async throws {
24+
let (one, two, three) = try await client.getMulti()
25+
await XCTAssertNoThrow(try await client.sendMulti(one: one, two: two, three: three),
26+
"getMulti() should receive simple type and send it back via sendMulti() successfully")
27+
}
28+
29+
func testComplex() async throws {
30+
let response = try await client.getComplex()
31+
await XCTAssertNoThrow(try await client.sendComplex(complex: response),
32+
"getComplex() should receive complex type and send it back via sendComplex() successfully")
33+
}
34+
35+
func testCustomErrors() async throws {
36+
let errors: [WebrpcError] = [
37+
.init(
38+
error: "WebrpcEndpoint",
39+
code: 0,
40+
message: "endpoint error",
41+
cause: "failed to read file: unexpected EOF",
42+
status: 400,
43+
errorKind: .webrpcEndpointError
44+
),
45+
.init(
46+
error: "Unauthorized",
47+
code: 1,
48+
message: "unauthorized",
49+
cause: "failed to verify JWT token",
50+
status: 401,
51+
errorKind: .unauthorizedError
52+
),
53+
.init(
54+
error: "ExpiredToken",
55+
code: 2,
56+
message: "expired token",
57+
cause: nil,
58+
status: 401,
59+
errorKind: .expiredTokenError
60+
),
61+
.init(
62+
error: "InvalidToken",
63+
code: 3,
64+
message: "invalid token",
65+
cause: nil,
66+
status: 401,
67+
errorKind: .invalidTokenError
68+
),
69+
.init(
70+
error: "Deactivated",
71+
code: 4,
72+
message: "account deactivated",
73+
cause: nil,
74+
status: 403,
75+
errorKind: .deactivatedError
76+
),
77+
.init(
78+
error: "ConfirmAccount",
79+
code: 5,
80+
message: "confirm your email",
81+
cause: nil,
82+
status: 403,
83+
errorKind: .confirmAccountError
84+
),
85+
.init(
86+
error: "AccessDenied",
87+
code: 6,
88+
message: "access denied",
89+
cause: nil,
90+
status: 403,
91+
errorKind: .accessDeniedError
92+
),
93+
.init(
94+
error: "MissingArgument",
95+
code: 7,
96+
message: "missing argument",
97+
cause: nil,
98+
status: 400,
99+
errorKind: .missingArgumentError
100+
),
101+
.init(
102+
error: "UnexpectedValue",
103+
code: 8,
104+
message: "unexpected value",
105+
cause: nil,
106+
status: 400,
107+
errorKind: .unexpectedValueError
108+
),
109+
.init(
110+
error: "RateLimited",
111+
code: 100,
112+
message: "too many requests",
113+
cause: "1000 req/min exceeded",
114+
status: 429,
115+
errorKind: .rateLimitedError
116+
),
117+
.init(
118+
error: "DatabaseDown",
119+
code: 101,
120+
message: "service outage",
121+
cause: nil,
122+
status: 503,
123+
errorKind: .databaseDownError
124+
),
125+
.init(
126+
error: "ElasticDown",
127+
code: 102,
128+
message: "search is degraded",
129+
cause: nil,
130+
status: 503,
131+
errorKind: .elasticDownError
132+
),
133+
.init(
134+
error: "NotImplemented",
135+
code: 103,
136+
message: "not implemented",
137+
cause: nil,
138+
status: 501,
139+
errorKind: .notImplementedError
140+
),
141+
.init(
142+
error: "UserNotFound",
143+
code: 200,
144+
message: "user not found",
145+
cause: nil,
146+
status: 400,
147+
errorKind: .userNotFoundError
148+
),
149+
.init(
150+
error: "UserBusy",
151+
code: 201,
152+
message: "user busy",
153+
cause: nil,
154+
status: 400,
155+
errorKind: .userBusyError
156+
),
157+
.init(
158+
error: "InvalidUsername",
159+
code: 202,
160+
message: "invalid username",
161+
cause: nil,
162+
status: 400,
163+
errorKind: .invalidUsernameError
164+
),
165+
.init(
166+
error: "FileTooBig",
167+
code: 300,
168+
message: "file is too big (max 1GB)",
169+
cause: nil,
170+
status: 400,
171+
errorKind: .fileTooBigError
172+
),
173+
.init(
174+
error: "FileInfected",
175+
code: 301,
176+
message: "file is infected",
177+
cause: nil,
178+
status: 400,
179+
errorKind: .fileInfectedError
180+
),
181+
.init(
182+
error: "FileType",
183+
code: 302,
184+
message: "unsupported file type",
185+
cause: ".wav is not supported",
186+
status: 400,
187+
errorKind: .fileTypeError
188+
)
189+
]
190+
for error in errors {
191+
do {
192+
try await client.getSchemaError(code: error.code)
193+
XCTFail("Expected to throw \(error)")
194+
} catch let err as WebrpcError {
195+
XCTAssertEqual(error.code, err.code)
196+
XCTAssertEqual(error.error, err.error)
197+
XCTAssertEqual(error.message, err.message)
198+
XCTAssertEqual(error.status, err.status)
199+
XCTAssertEqual(error.cause, err.cause)
200+
XCTAssertEqual(error.kind, err.kind)
201+
} catch let err {
202+
XCTFail("Expected to throw \(error) but got \(err) instead")
203+
}
204+
}
205+
}
206+
}
207+
208+
extension XCTest {
209+
func XCTAssertThrowsError<T: Sendable>(
210+
_ expression: @autoclosure () async throws -> T,
211+
_ message: @autoclosure () -> String = "",
212+
file: StaticString = #filePath,
213+
line: UInt = #line,
214+
_ errorHandler: (_ error: Error) -> Void = { _ in }
215+
) async {
216+
do {
217+
_ = try await expression()
218+
XCTFail(message(), file: file, line: line)
219+
} catch {
220+
errorHandler(error)
221+
}
222+
}
223+
224+
func XCTAssertNoThrow<T: Sendable>(
225+
_ expression: @autoclosure () async throws -> T,
226+
_ message: @autoclosure () -> String = "",
227+
file: StaticString = #filePath,
228+
line: UInt = #line
229+
) async {
230+
do {
231+
_ = try await expression()
232+
} catch {
233+
XCTFail(message(), file: file, line: line)
234+
}
235+
}
236+
}

Tests/download.sh

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/bash
2+
set -e
3+
4+
VERSION="${1}"
5+
DIR="${2}"
6+
[[ -z "$VERSION" || -z "$DIR" ]] && { echo "Usage: $0 <webrpc-version> <dir>"; exit 1; }
7+
8+
mkdir -p "$DIR"
9+
10+
# Download webrpc binaries if not available locally
11+
OS="$(basename $(uname -o | tr A-Z a-z))"
12+
ARCH="$(uname -m | sed 's/x86_64/amd64/')"
13+
if [[ ! -f "$DIR/webrpc-gen" ]]; then
14+
curl -o "$DIR/webrpc-gen" -fLJO "https://github.com/webrpc/webrpc/releases/download/$VERSION/webrpc-gen.$OS-$ARCH"
15+
chmod +x "$DIR/webrpc-gen"
16+
fi
17+
if [[ ! -f "$DIR/webrpc-test" ]]; then
18+
curl -o "$DIR/webrpc-test" -fLJO "https://github.com/webrpc/webrpc/releases/download/$VERSION/webrpc-test.$OS-$ARCH"
19+
chmod +x "$DIR/webrpc-test"
20+
fi

0 commit comments

Comments
 (0)