Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

33 changes: 21 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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"))
Expand All @@ -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.
Expand All @@ -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: [
...
Expand All @@ -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
```
35 changes: 31 additions & 4 deletions example/Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions example/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
],
Expand All @@ -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()
Expand All @@ -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()
Expand All @@ -79,7 +82,7 @@ let package = Package(
permissions: [.writeToPackageDirectory(reason: "Place generated code")]
),
dependencies: [
.product(name: "codegen", package: "CallableKit"),
.product(name: "codegen", package: "CallableKitCodegen"),
]
)
]
Expand Down
25 changes: 23 additions & 2 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
3 changes: 3 additions & 0 deletions example/test.sh
Original file line number Diff line number Diff line change
@@ -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

Expand Down
Loading