CallableKit provides typesafe rpc with Swift server.
- Swift (with Foundation)
- AsyncHTTPClient also adaptable
- TypeScript (with fetch)
Define interface protocol and share the module to server and client.
Interface protocols must be annotated with @Callable
import CallableKit
@CallablepublicprotocolEchoServiceProtocol{func hello(request:EchoHelloRequest)asyncthrows->EchoHelloResponse}publicstructEchoHelloRequest:Codable,Sendable{publicinit(name:String){self.name = name
}publicvarname:String}publicstructEchoHelloResponse:Codable,Sendable{publicinit(message:String){self.message = message
}publicvarmessage:String}On the server side, you prepare the implementation of the protocol and register it for routing using the Transport module.
import APIDefinition // Your interface module
import CallableKitVaporTransport
import Vapor
structEchoService:EchoServiceProtocol{func hello(request:EchoHelloRequest)asyncthrows->EchoHelloResponse{return.init(message:"Hello, \(request.name)!")}}letapp=tryawaitApplication.make()
// Swift macro generates `configureEchoServiceProtocol`
configureEchoServiceProtocol(transport:VaporTransport(router: app.routes){ _ inEchoService()})tryawait app.execute()tryawait app.asyncShutdown()Client can call the functions through a stub client.
import APIDefinition
import CallableKitURLSessionStub
letstubClient:someStubClientProtocol=URLSessionStubClient(
baseURL:URL(string:"http://127.0.0.1:8080")!
)
// EchoServiceProtocolStub is also generated by Swift macro
letechoClient=EchoServiceProtocolStub(client: stubClient)letres=tryawait echoClient.hello(request:.init(name:"Swift"))print(res.message) // Hello, Swift!TypeScript client is also supported. It needs manual code generation.
conststub=createStubClient("http://127.0.0.1:8080");constechoClient=bindEcho(stub);constres/*: { message: string }*/=awaitechoClient.hello({name: "TypeScript"});console.log(res.message);// Hello, TypeScript!Swift types are coverted to TypeScript types powered by CodableToTypeScript
- Checkout CallableKitCodegen repo and simply run executable command
$ swift run codegen Sources/APIDefinition \
--ts_out TSClient/src/GenMint is useful to checkout and run.
or
Use from package plugin (see example)
Add plugin target in your Package.swift (or add dedicated Package.swift for independency)
dependencies:[....package(url:"https://github.com/sidepelican/CallableKitCodegen.git", from:"1.0.0"),],targets:[....plugin(
name:"CodegenPlugin",
capability:.command(
intent:.custom(verb:"codegen", description:"Generate codes from Sources/APIDefinition"),
permissions:[.writeToPackageDirectory(reason:"Place generated code")]),
dependencies:[.product(name:"codegen",package:"CallableKitCodegen"),]),]swift run codegen