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
53 changes: 30 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ CallableKit provides typesafe rpc with Swift server

# Example

- Define interface protocol and share this module for server and client.
Define interface protocol and share the module to server and client.
Interface protocols must be annotated with `@Callable`

```swift
@Callable
public protocol EchoServiceProtocol {
func hello(request: EchoHelloRequest) async throws -> EchoHelloResponse
}
Expand All @@ -31,11 +33,11 @@ public struct EchoHelloResponse: Codable, Sendable {
}
```

- Run code generation

- Server implements thet protocol and register to routes.
Server implements thet protocol and register to routes.

```swift
import APIDefinition // Your interface module
import CallableKitVaporTransport
import Vapor

struct EchoService: EchoServiceProtocol {
Expand All @@ -44,34 +46,41 @@ struct EchoService: EchoServiceProtocol {
}
}

let app = Application()
defer { app.shutdown() }
let echoProvider = EchoServiceProvider { _ in // EchoServiceProvider is generated type
let app = try await Application.make()

// Swift macro generates `configureEchoServiceProtocol`
configureEchoServiceProtocol(transport: VaporTransport(router: app.routes) { _ in
EchoService()
}
try app.register(collection: echoProvider)
try app.run()
})

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 stub client. Using the same protocol.

```swift
let client: some StubClientProtocol = FoundationHTTPStubClient(
baseURL: URL(string: "http://127.0.0.1:8080")!,
import APIDefinition
import CallableKitURLSessionStub

let stubClient: some StubClientProtocol = URLSessionStubClient(
baseURL: URL(string: "http://127.0.0.1:8080")!
)
// .echo.hello is generated extension
let res = try await client.echo.hello(request: .init(name: "Swift"))
// EchoServiceProtocolStub is also generated by Swift macro
let echoClient = EchoServiceProtocolStub(client: stubClient)
let res = try await echoClient.hello(request: .init(name: "Swift"))
print(res.message) // Hello, Swift!
```

- TypeScript client also supported!
TypeScript client is also supported.
It needs manual code generation.


```ts
const stub = createStubClient("http://127.0.0.1:8080");
const echoClient = bindEcho(stub);
const res = await echoClient.hello({ name: "TypeScript" });
const res/*: { message: string }*/ = await echoClient.hello({ name: "TypeScript" });
console.log(res.message); // Hello, TypeScript!
// ^? res: { message: string }
```

Swift types are coverted to TS types powered by [CodableToTypeScript](https://github.com/omochi/CodableToTypeScript)
Expand All @@ -82,23 +91,21 @@ Swift types are coverted to TS types powered by [CodableToTypeScript](https://gi

```sh
$ swift run codegen Sources/APIDefinition \
--client_out Sources/Client/Gen \
--vapor_out Sources/Server/Gen \
--ts_out TSClient/src/Gen \
```

[Mint](https://github.com/yonaskolb/Mint) is useful to checkout and run.

or
or

- Use from package plugin (see [example](https://github.com/sidepelican/CallableKit/tree/main/example))

Add plugin target in your Package.swift (or add dedicated Package.swift for independency)

```swift
dependencies: [
...
.package(url: "https://github.com/sidepelican/CallableKit", from: "1.0.0"),
.package(url: "https://github.com/sidepelican/CallableKit.git", from: "1.0.0"),
],
targets: [
...
Expand Down
2 changes: 1 addition & 1 deletion Sources/CallableKit/CallableKitEmpty.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
@usableFromInline internal struct CallableKitEmpty: Codable {
@usableFromInline internal struct CallableKitEmpty: Codable, Sendable {
@usableFromInline init() {}
}
10 changes: 5 additions & 5 deletions Sources/CallableKit/ServiceTransport.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
public protocol ServiceTransport<Service> {
associatedtype Service

func register<Request: Decodable>(
func register<Request: Decodable & Sendable>(
path: String,
methodSelector: @escaping @Sendable (Service.Type) -> (Service) -> (Request) async throws -> Void
)

func register<Response: Encodable>(
func register<Response: Encodable & Sendable>(
path: String,
methodSelector: @escaping @Sendable (Service.Type) -> (Service) -> () async throws -> Response
)
Expand All @@ -16,14 +16,14 @@ public protocol ServiceTransport<Service> {
methodSelector: @escaping @Sendable (Service.Type) -> (Service) -> () async throws -> Void
)

func register<Request: Decodable, Response: Encodable>(
func register<Request: Decodable & Sendable, Response: Encodable & Sendable>(
path: String,
methodSelector: @escaping @Sendable (Service.Type) -> (Service) -> (Request) async throws -> Response
)
}

extension ServiceTransport {
@inlinable public func register<Request: Decodable>(
@inlinable public func register<Request: Decodable & Sendable>(
path: String,
methodSelector: @escaping @Sendable (Service.Type) -> (Service) -> (Request) async throws -> Void
) {
Expand All @@ -37,7 +37,7 @@ extension ServiceTransport {
}
}

@inlinable public func register<Response: Encodable>(
@inlinable public func register<Response: Encodable & Sendable>(
path: String,
methodSelector: @escaping @Sendable (Service.Type) -> (Service) -> () async throws -> Response
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ struct ErrorFrame: Decodable, CustomStringConvertible, LocalizedError {
var errorDescription: String? { description }
}

@main struct Main {
@main struct ClientMain {
static func main() async throws {
let client: some StubClientProtocol = URLSessionStubClient(
baseURL: URL(string: "http://127.0.0.1:8080")!,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct ErrorMiddleware<Context: RequestContext>: MiddlewareProtocol {
}
}

@main struct Main {
@main struct HBMain {
static func main() async throws {
let router = Router()
router.add(middleware: ErrorMiddleware())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import CallableKitVaporTransport
import Vapor
import Service

@main struct Main {
@main struct VaporMain {
static func main() async throws {
let app = try await Application.make()

Expand Down
Loading