I had a chance to test a generated client out with Vapor 4 and it works great! I've included the code I used below for reference.
The biggest issue I ran into getting this up and running was configuring protoc
. I noticed you have a Makefile
but I couldn't really figure out how to get that working. It seems like it's built specifically for the grpc-swift
repo and it was difficult (for me at least) to parse what was happening inside due to all the variables.
I ended up installing SwiftProtobuf via brew install swift-protobuf
. That worked great, but I still needed protoc-gen-grpc-swift
. After a lot of debugging strange errors, I finally realized if I build grpc-swift
in release mode, then put that executable in my bin, protoc
can find it automatically. Once all said and done, I was able to use this command:
protoc HelloWorld.proto \
--proto_path=Sources/App \
--swift_out=Sources/App \
--grpc-swift_out=Sources/App
That finally generated both the HelloWorld.pb.swift
and HelloWorld.grpc.swift
files where I wanted them.
Two takeaways from setup:
- It would be awesome if you could
brew install swift-grpc
or at least clone grpc/swift-grpc and do make install
- The docs I found seemed more geared toward running the grpc-swift repo's examples, and not toward using it in your own project. In fairness, I might have just glossed over those accidentally.
Some takeaways from the actual code:
- I'm initializing a new
ClientConnection
each request. Is this the recommended pattern or do I need to keep a shared client for connection pooling?
- I got a strange error
Missing package product 'Logging'
if I didn't explicitly include apple/swift-log
in my project. I haven't seen this before and I'm not sure why I'd need to do that. @weissi any ideas?
Here's the main.swift
file I used.
import GRPC
import Vapor
var env = try Environment.detect()
try LoggingSystem.bootstrap(from: &env)
let app = Application(env)
defer { app.shutdown() }
app.get("greeting") { req -> EventLoopFuture<String> in
// Provide some basic configuration for the connection, in this case we connect to an endpoint on
// localhost at the given port.
let configuration = ClientConnection.Configuration(
target: .hostAndPort("localhost", 50323),
eventLoopGroup: req.eventLoop
)
// Create a connection using the configuration.
let connection = ClientConnection(configuration: configuration)
// Provide the connection to the generated client.
let greeter = Helloworld_GreeterServiceClient(connection: connection)
// Form the request with the name, if one was provided.
let request = Helloworld_HelloRequest.with {
$0.name = req.query["name"] ?? ""
}
// Make the RPC call to the server.
let sayHello = greeter.sayHello(request)
// map response
return sayHello.response.map { reply in
reply.message
}
}
try app.run()
$ http get localhost:8080/greeting name==Vapor
HTTP/1.1 200 OK
content-length: 12
content-type: text/plain; charset=utf-8
Hello Vapor!
Finally, the Package.swift
:
// swift-tools-version:5.1
import PackageDescription
let package = Package(
name: "foo",
platforms: [
.macOS(.v10_14)
],
dependencies: [
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0-beta"),
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0-alpha"),
// Not sure why this one is needed.
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),
],
targets: [
.target(name: "App", dependencies: ["Logging", "GRPC", "Vapor"])
]
)