|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +published: true |
| 4 | +date: 2025-02-14 10:00:00 |
| 5 | +title: Introducing gRPC Swift 2 |
| 6 | +author: [george-barnett, gus-cairo] |
| 7 | +--- |
| 8 | + |
| 9 | +Say hello to gRPC Swift 2: a major update that brings first-class concurrency |
| 10 | +support and more expressive APIs for a seamless developer experience. |
| 11 | + |
| 12 | +Inconsistent and poorly documented service APIs create integration headaches for |
| 13 | +developers. gRPC is a modern, high-performance framework for building service |
| 14 | +APIs, enabling efficient communication between systems over a network. |
| 15 | + |
| 16 | +Since services may be written with a different language than their clients, most |
| 17 | +gRPC services use [Protocol Buffers](https://protobuf.dev/) (or “protobufs”) to |
| 18 | +define their APIs and the messages exchanged between clients and servers. |
| 19 | +Service contracts are defined in a neutral, cross-platform format using `.proto` |
| 20 | +files. This is the foundation of your service, not an artefact of its |
| 21 | +implementation. And thanks to the format’s efficient binary serialization, these |
| 22 | +messages are typically smaller and faster to process than other standard formats |
| 23 | +like JSON. |
| 24 | + |
| 25 | +gRPC Swift is one of a family of similar tools that use the Protocol Buffers |
| 26 | +contract to generate code in the language you’re working with, making it easy to |
| 27 | +build clients and servers that adhere to your service contract. And the new gRPC |
| 28 | +Swift 2 offers an idiomatic, cross-platform, performant and feature-rich library |
| 29 | +for building highly-scalable services. |
| 30 | + |
| 31 | +This release is a major update that takes advantage of many modern Swift |
| 32 | +features for cross-platform services development. When gRPC Swift was first |
| 33 | +developed back in 2018, Swift had not yet introduced concurrency features like |
| 34 | +[async/await](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency/), |
| 35 | +so it was instead based on SwiftNIO’s event-driven concurrency model. For |
| 36 | +developers unfamiliar with these concepts, the prior version of gRPC Swift |
| 37 | +presented a steep learning curve. Now that Swift’s modern concurrency model is |
| 38 | +fully established, we seized the opportunity to rethink gRPC Swift for today’s |
| 39 | +Swift, incorporating lessons learned from our years of use at Apple for building |
| 40 | +internet-scale services. |
| 41 | + |
| 42 | +## Highlights |
| 43 | + |
| 44 | +* Modern, flexible, and easy-to-use APIs with idiomatic generated code. |
| 45 | +* Full support for building services and clients on Linux and Apple platforms. |
| 46 | +* Pluggable transports including a high-performance HTTP/2 transport built on |
| 47 | + top of [SwiftNIO](https://github.com/apple/swift-nio), and an in-process |
| 48 | + transport which is great for testing. |
| 49 | +* Smart client features like client-side load balancing, a pluggable name |
| 50 | + resolution mechanism and automatic retries. |
| 51 | +* A flexible interceptor layer allowing you to implement cross-cutting logic |
| 52 | + like authentication, logging, and metrics. |
| 53 | + |
| 54 | +## Hello, swift.org! |
| 55 | + |
| 56 | +Consider the canonical "hello world" service with a single API which returns a |
| 57 | +greeting. You might define it like this in a `.proto` file: |
| 58 | + |
| 59 | +```proto |
| 60 | +syntax = "proto3"; |
| 61 | +
|
| 62 | +service GreetingService { |
| 63 | + // Returns a personalized greeting. |
| 64 | + rpc SayHello(SayHelloRequest) returns (SayHelloResponse); |
| 65 | +} |
| 66 | +
|
| 67 | +message SayHelloRequest { |
| 68 | + // The name of the person to greet. |
| 69 | + string name = 1; |
| 70 | +} |
| 71 | +
|
| 72 | +message SayHelloResponse { |
| 73 | + // The personalized greeting message. |
| 74 | + string message = 1; |
| 75 | +} |
| 76 | +``` |
| 77 | + |
| 78 | +gRPC can be configured to generate: |
| 79 | + |
| 80 | +* Service code so you can implement the business logic. |
| 81 | +* Client code to make requests against the service. |
| 82 | + |
| 83 | +Code for messages is generated by |
| 84 | +[SwiftProtobuf](https://github.com/apple/swift-protobuf/) and used in |
| 85 | +conjunction with the generated gRPC code. |
| 86 | + |
| 87 | +### Generated Service Code |
| 88 | + |
| 89 | +The generated code includes a Swift protocol describing the requirements of the |
| 90 | +service with one method for each `rpc` in the service definition. To implement |
| 91 | +the business logic of your service just implement one of the service protocols. |
| 92 | +The example below uses the `SimpleServiceProtocol` which is the highest level |
| 93 | +API. If you need more flexibility you can use the `ServiceProtocol` or |
| 94 | +`StreamingServiceProtocol` which trade off conciseness for flexibility. |
| 95 | + |
| 96 | +To start the service you need to create a server configured to use a transport |
| 97 | +and an instance of your service: |
| 98 | + |
| 99 | +```swift |
| 100 | +import GRPCCore |
| 101 | +import GRPCNIOTransportHTTP2 |
| 102 | + |
| 103 | +struct Greeter: GreetingService.SimpleServiceProtocol { |
| 104 | + func sayHello( |
| 105 | + request: SayHelloRequest, |
| 106 | + context: ServerContext |
| 107 | + ) async throws -> SayHelloResponse { |
| 108 | + return SayHelloResponse.with { |
| 109 | + $0.message = "Hello, \(request.name)!" |
| 110 | + } |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +@main |
| 115 | +struct GreeterServer { |
| 116 | + static func main() async throws { |
| 117 | + // Create a plaintext server using the SwiftNIO based HTTP/2 transport |
| 118 | + // listening on 128.0.0.1:8080. |
| 119 | + let server = GRPCServer( |
| 120 | + transport: .http2NIOPosix( |
| 121 | + address: .ipv4(host: "127.0.0.1", port: 8080), |
| 122 | + transportSecurity: .plaintext |
| 123 | + ), |
| 124 | + services: [Greeter()] |
| 125 | + ) |
| 126 | + |
| 127 | + // Start serving indefinitely. |
| 128 | + try await server.serve() |
| 129 | + } |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +### Generated Client Code |
| 134 | + |
| 135 | +gRPC generates an idiomatic client for you, simplifying service calls. To use |
| 136 | +it, first create a raw client and wrap it with the generated client specific to |
| 137 | +your service. This generated client provides a type-safe way for you to easily |
| 138 | +interact with your service. |
| 139 | + |
| 140 | +```swift |
| 141 | +import GRPCCore |
| 142 | +import GRPCNIOTransportHTTP2 |
| 143 | + |
| 144 | +@main |
| 145 | +struct SayHello { |
| 146 | + static func main() async throws { |
| 147 | + // Create a plaintext client using the SwiftNIO based HTTP/2 transport |
| 148 | + // connecting to a service listening on 128.0.0.1:8080. |
| 149 | + try await withGRPCClient( |
| 150 | + transport: .http2NIOPosix( |
| 151 | + target: .dns(host: "127.0.0.1", port: 8080), |
| 152 | + transportSecurity: .plaintext |
| 153 | + ) |
| 154 | + ) { client in |
| 155 | + let greeter = GreetingService.Client(wrapping: client) |
| 156 | + let greeting = try await greeter.sayHello(.with { $0.name = "swift.org" }) |
| 157 | + print(greeting.message) |
| 158 | + } |
| 159 | + } |
| 160 | +} |
| 161 | +``` |
| 162 | + |
| 163 | +## Package Ecosystem |
| 164 | + |
| 165 | +gRPC Swift 2 was designed with flexibility in mind. It's distributed as a |
| 166 | +collection of packages, allowing you to pick and choose the components which |
| 167 | +best suit your needs. These features are provided by the following packages: |
| 168 | + |
| 169 | +* [grpc/grpc-swift](https://github.com/grpc/grpc-swift) provides runtime |
| 170 | + abstractions and types. |
| 171 | +* [grpc/grpc-swift-nio-transport](https://github.com/grpc/grpc-swift-nio-transport) |
| 172 | + implements client and server transports using HTTP/2 and is built on top of |
| 173 | + SwiftNIO. |
| 174 | +* [grpc/grpc-swift-protobuf](https://github.com/grpc/grpc-swift-protobuf) |
| 175 | + integrates with [SwiftProtobuf](https://github.com/apple/swift-protobuf/) to |
| 176 | + provide a code generator for services defined in `.proto` files. |
| 177 | +* [grpc/grpc-swift-extras](https://github.com/grpc/grpc-swift-extras) includes |
| 178 | + common gRPC add-ons, like the reflection and health services, integrations |
| 179 | + with [Swift Service |
| 180 | + Lifecycle](https://github.com/swift-server/swift-service-lifecycle), and |
| 181 | + interceptors to trace RPCs using [OpenTelemetry](https://opentelemetry.io/). |
| 182 | + |
| 183 | +## Next Steps |
| 184 | + |
| 185 | +To get started with gRPC Swift 2 check out the [tutorials and |
| 186 | +documentation](https://swiftpackageindex.com/grpc/grpc-swift/documentation) |
| 187 | +which are hosted on the Swift Package Index, or try out one of the examples in |
| 188 | +the [grpc/grpc-swift](https://github.com/grpc/grpc-swift) repository. |
| 189 | + |
| 190 | +If you have feature requests, want to report a bug, or would like to contribute |
| 191 | +to the project then please reach out to us on |
| 192 | +[GitHub](https://github.com/grpc/grpc-swift) or join us on the [Swift |
| 193 | +forums](https://forums.swift.org/c/related-projects/grpc-swift/). Let’s connect! |
0 commit comments