diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 912c776..d08275b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,10 @@ jobs: steps: - uses: actions/checkout@v4 - run: swift test - # - run: npm ci - # working-directory: example/TSClient - # - run: ./test.sh vapor - # - run: ./test.sh hummingbird + - run: npm ci + working-directory: example/TSClient + - run: ./test.sh vapor + working-directory: example + - run: ./test.sh hummingbird + working-directory: example + diff --git a/README.md b/README.md index 5a95d25..c526cf5 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,26 @@ # CallableKit -CallableKit provides typesafe rpc with Swift server +CallableKit provides typesafe rpc with Swift server. + +### Supported server frameworks + +- [Vapor](https://github.com/vapor/vapor) +- [Hummingbird](https://github.com/hummingbird-project/hummingbird) ### Supported clients - Swift (with Foundation) + - [AsyncHTTPClient](https://github.com/swift-server/async-http-client) also adaptable - TypeScript (with fetch) -# Example +## Usage Define interface protocol and share the module to server and client. Interface protocols must be annotated with `@Callable` ```swift +import CallableKit + @Callable public protocol EchoServiceProtocol { func hello(request: EchoHelloRequest) async throws -> EchoHelloResponse @@ -33,7 +41,7 @@ public struct EchoHelloResponse: Codable, Sendable { } ``` -Server implements thet protocol and register to routes. +On the server side, you prepare the implementation of the protocol and register it for routing using the `Transport` module. ```swift import APIDefinition // Your interface module @@ -57,7 +65,7 @@ try await app.execute() try await app.asyncShutdown() ``` -Client can call the functions through stub client. Using the same protocol. +Client can call the functions through a stub client. ```swift import APIDefinition @@ -66,6 +74,7 @@ import CallableKitURLSessionStub let stubClient: some StubClientProtocol = URLSessionStubClient( baseURL: URL(string: "http://127.0.0.1:8080")! ) + // EchoServiceProtocolStub is also generated by Swift macro let echoClient = EchoServiceProtocolStub(client: stubClient) let res = try await echoClient.hello(request: .init(name: "Swift")) @@ -83,15 +92,15 @@ const res/*: { message: string }*/ = await echoClient.hello({ name: "TypeScript" console.log(res.message); // Hello, TypeScript! ``` -Swift types are coverted to TS types powered by [CodableToTypeScript](https://github.com/omochi/CodableToTypeScript) +Swift types are coverted to TypeScript types powered by [CodableToTypeScript](https://github.com/omochi/CodableToTypeScript) -# Run code generation +## Run code generation -- Checkout this repo and simply run executable command +- Checkout [CallableKitCodegen](https://github.com/sidepelican/CallableKitCodegen) repo and simply run executable command ```sh $ swift run codegen Sources/APIDefinition \ - --ts_out TSClient/src/Gen \ + --ts_out TSClient/src/Gen ``` [Mint](https://github.com/yonaskolb/Mint) is useful to checkout and run. @@ -105,7 +114,7 @@ or ```swift dependencies: [ ... - .package(url: "https://github.com/sidepelican/CallableKit.git", from: "1.0.0"), + .package(url: "https://github.com/sidepelican/CallableKitCodegen.git", from: "1.0.0"), ], targets: [ ... @@ -116,12 +125,12 @@ or permissions: [.writeToPackageDirectory(reason: "Place generated code")] ), dependencies: [ - .product(name: "codegen", package: "CallableKit"), + .product(name: "codegen", package: "CallableKitCodegen"), ] - ) + ), ] ``` ```sh -$ swift run codegen +swift run codegen ``` diff --git a/example/Package.resolved b/example/Package.resolved index 7309776..c21c87f 100644 --- a/example/Package.resolved +++ b/example/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "f17cbec788f41a8520f2a0678c0cafe43ec3cc9c912babd1084f8df66e461370", + "originHash" : "42d8ad0a61f47093d5f11de7a70d56828bddf5c8308092d6e573fa04a7e84d05", "pins" : [ { "identity" : "async-http-client", @@ -19,6 +19,33 @@ "version" : "1.18.0" } }, + { + "identity" : "callablekitcodegen", + "kind" : "remoteSourceControl", + "location" : "https://github.com/sidepelican/CallableKitCodegen.git", + "state" : { + "branch" : "main", + "revision" : "3886d8822d49c9b3e917b07b72fa42b65d3b805d" + } + }, + { + "identity" : "callablekithummingbirdtransport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/sidepelican/CallableKitHummingbirdTransport.git", + "state" : { + "branch" : "main", + "revision" : "855d34b06f28b232addbec2850ee10f837f4d43f" + } + }, + { + "identity" : "callablekitvaportransport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/sidepelican/CallableKitVaporTransport.git", + "state" : { + "branch" : "main", + "revision" : "c8bacae8a9c86f0e4ab10e2d092d34564747ad54" + } + }, { "identity" : "codabletotypescript", "kind" : "remoteSourceControl", @@ -76,10 +103,10 @@ { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-argument-parser", + "location" : "https://github.com/apple/swift-argument-parser.git", "state" : { - "revision" : "fee6933f37fde9a5e12a1e4aeaa93fe60116ff2a", - "version" : "1.2.2" + "revision" : "41982a3656a71c768319979febd796c6fd111d5c", + "version" : "1.5.0" } }, { diff --git a/example/Package.swift b/example/Package.swift index 4dee88e..cb6f0c0 100644 --- a/example/Package.swift +++ b/example/Package.swift @@ -27,7 +27,10 @@ let package = Package( name: "MyApplication", platforms: [.macOS(.v14)], dependencies: [ - .package(path: "../"), + .package(url: "https://github.com/sidepelican/CallableKit.git", branch: "main"), + .package(url: "https://github.com/sidepelican/CallableKitCodegen.git", branch: "main"), + .package(url: "https://github.com/sidepelican/CallableKitVaporTransport.git", branch: "main"), + .package(url: "https://github.com/sidepelican/CallableKitHummingbirdTransport.git", branch: "main"), .package(url: "https://github.com/vapor/vapor.git", from: "4.106.7"), .package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.5.0"), ], @@ -50,7 +53,7 @@ let package = Package( name: "VaporServer", dependencies: [ .product(name: "Vapor", package: "vapor"), - .product(name: "CallableKitVaporTransport", package: "CallableKit"), + .product(name: "CallableKitVaporTransport", package: "CallableKitVaporTransport"), "Service", ], swiftSettings: swiftSettings() @@ -59,7 +62,7 @@ let package = Package( name: "HBServer", dependencies: [ .product(name: "Hummingbird", package: "hummingbird"), - .product(name: "CallableKitHummingbirdTransport", package: "CallableKit"), + .product(name: "CallableKitHummingbirdTransport", package: "CallableKitHummingbirdTransport"), "Service", ], swiftSettings: swiftSettings() @@ -79,7 +82,7 @@ let package = Package( permissions: [.writeToPackageDirectory(reason: "Place generated code")] ), dependencies: [ - .product(name: "codegen", package: "CallableKit"), + .product(name: "codegen", package: "CallableKitCodegen"), ] ) ] diff --git a/example/README.md b/example/README.md index 24eecf6..5f6c555 100644 --- a/example/README.md +++ b/example/README.md @@ -1,8 +1,29 @@ # example -A description of this package. +This is an example of CallableKit usage. +API definition, server, and client are all implemented in one package, but each can be split up. -## Codegen +## Setup + +Override `CallableKit` with local package. + +```sh +swift package edit --path ../ CallableKit +``` + +## Run test + +Select the server-side framework to test. + +```sh +./test.sh vapor +``` + +```sh +./test.sh hummingbird +``` + +## Manual code generation ```sh swift package --allow-writing-to-package-directory codegen diff --git a/example/test.sh b/example/test.sh index afc35cb..b82a040 100755 --- a/example/test.sh +++ b/example/test.sh @@ -1,6 +1,9 @@ #!/bin/bash -ue set -o pipefail +set +e +swift package edit --path ../ CallableKit +set -e swift package --allow-writing-to-package-directory codegen swift build