|
20 | 20 | Before we can write any code we need to create a new Swift Package and configure it |
21 | 21 | to depend on gRPC Swift. |
22 | 22 |
|
| 23 | + As a prerequisite you must have the Protocol Buffers compiler (`protoc`) installed. You can |
| 24 | + find the instructions for doing this in the [gRPC Swift Protobuf |
| 25 | + documentation](https://swiftpackageindex.com/grpc/grpc-swift-protobuf/documentation/grpcprotobuf/installing-protoc). |
| 26 | + The remainder of this tutorial assumes you installed `protoc` and it's available in |
| 27 | + your `$PATH`. |
| 28 | + |
| 29 | + You may notice that the `swift` commands are all prefixed with `PROTOC_PATH=$(which protoc)`, |
| 30 | + this is to let the build system know where `protoc` is located so that it can generate stubs |
| 31 | + for you. You can read more about it in the [gRPC Swift Protobuf |
| 32 | + documentation](https://swiftpackageindex.com/grpc/grpc-swift-protobuf/documentation/grpcprotobuf/generating-stubs). |
| 33 | + |
23 | 34 | @Steps { |
24 | 35 | @Step { |
25 | 36 | Create a new directory called for the package called `RouteGuide`. |
|
84 | 95 |
|
85 | 96 | @Code(name: "Package.swift", file: "route-guide-sec01-step08-description.swift") |
86 | 97 | } |
| 98 | + |
| 99 | + @Step { |
| 100 | + We'll also add a build plugin. This allows the build system to generate gRPC code at build |
| 101 | + time rather than having to generate it with separate tooling. |
| 102 | + |
| 103 | + @Code(name: "Package.swift", file: "route-guide-sec01-step09-plugin.swift") |
| 104 | + } |
| 105 | + |
| 106 | + @Step { |
| 107 | + A configuration file is required so that the plugin knows what to generate. Create |
| 108 | + a JSON file in the `Sources/Protos` directory called `grpc-swift-proto-generator-config.json` |
| 109 | + with this content. |
| 110 | + |
| 111 | + The name of the file (`grpc-swift-proto-generator-config.json`) is important: the plugin |
| 112 | + looks for files matching this name in the source directory of your target. |
| 113 | + |
| 114 | + @Code(name: "Sources/Protos/grpc-swift-proto-generator-config.json", file: "route-guide-sec01-step10-plugin-config.json") |
| 115 | + } |
87 | 116 | } |
88 | 117 | } |
89 | 118 |
|
|
93 | 122 |
|
94 | 123 | @Steps { |
95 | 124 | @Step { |
96 | | - Create a new empty file in the `Protos` directory called `route_guide.proto`. We'll use |
97 | | - the "proto3" syntax and our service will be part of the "routeguide" package. |
| 125 | + Create a new directory in the `Sources/Protos` directory called `routeguide` |
| 126 | + using `mkdir Sources/Protos/routeguide`. |
| 127 | + } |
| 128 | + |
| 129 | + @Step { |
| 130 | + Create a new empty file in the `Sources/Protos/routeguide` directory |
| 131 | + called `route_guide.proto`. We'll use the "proto3" syntax and our service will be part of |
| 132 | + the "routeguide" package. |
98 | 133 |
|
99 | | - @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step01-import.proto") |
| 134 | + It's good practice to organize your `.proto` files according to the package they are |
| 135 | + declared in, that's why we created the `routeguide` directory to match the "routeguide" |
| 136 | + package name. |
| 137 | + |
| 138 | + @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step01-import.proto") |
100 | 139 | } |
101 | 140 |
|
102 | 141 | @Step { |
103 | 142 | To define a service we create a named `service` in the `.proto` file. |
104 | 143 |
|
105 | | - @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step02-service.proto") |
| 144 | + @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step02-service.proto") |
106 | 145 | } |
107 | 146 |
|
108 | 147 | @Step { |
|
113 | 152 | A *unary RPC* where the client sends a request to the server using the stub |
114 | 153 | and waits for a response to come back, just like a normal function call. |
115 | 154 |
|
116 | | - @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step03-unary.proto") |
| 155 | + @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step03-unary.proto") |
117 | 156 | } |
118 | 157 |
|
119 | 158 | @Step { |
|
123 | 162 | example, you specify a server-side streaming method by placing the `stream` |
124 | 163 | keyword before the *response* type. |
125 | 164 |
|
126 | | - @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step04-server-streaming.proto") |
| 165 | + @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step04-server-streaming.proto") |
127 | 166 | } |
128 | 167 |
|
129 | 168 | @Step { |
|
133 | 172 | and return its response. You specify a client-side streaming method by placing |
134 | 173 | the `stream` keyword before the *request* type. |
135 | 174 |
|
136 | | - @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step05-client-streaming.proto") |
| 175 | + @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step05-client-streaming.proto") |
137 | 176 | } |
138 | 177 |
|
139 | 178 | @Step { |
|
146 | 185 | stream is preserved. You specify this type of method by placing the `stream` |
147 | 186 | keyword before both the request and the response. |
148 | 187 |
|
149 | | - @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step06-bidi-streaming.proto") |
| 188 | + @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step06-bidi-streaming.proto") |
150 | 189 | } |
151 | 190 |
|
152 | 191 | @Step { |
153 | 192 | The `.proto` file also contains the Protocol Buffers message type definitions for all |
154 | 193 | request and response messages used by the service. |
155 | 194 |
|
156 | | - @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step07-messages.proto") |
| 195 | + @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step07-messages.proto") |
157 | 196 | } |
158 | 197 | } |
159 | 198 | } |
160 | 199 |
|
161 | 200 | @Section(title: "Generating client and server code") { |
162 | 201 | Next we need to generate the gRPC client and server interfaces from our `.proto` |
163 | | - service definition. We do this using the Protocol Buffer compiler, `protoc`, with |
164 | | - two plugins: one with support for Swift (via [Swift Protobuf](https://github.com/apple/swift-protobuf)) |
165 | | - and the other for gRPC. This section assumes you already have `protoc` installed. |
| 202 | + service definition. As we're using the build plugin we just need to build our project. |
166 | 203 |
|
167 | 204 | To learn more about generating code check out the <doc:Generating-stubs> article. |
168 | 205 |
|
169 | 206 | @Steps { |
170 | 207 | @Step { |
171 | | - First we need to build the two plugins for `protoc`, `protoc-gen-swift` and |
172 | | - `protoc-gen-grpc-swift`. |
173 | | - |
174 | | - @Code(name: "Console", file: "route-guide-sec03-step01-protoc-plugins.txt") |
175 | | - } |
176 | | - |
177 | | - @Step { |
178 | | - We'll generate the code into a separate directory within `Sources` called `Generated` which |
179 | | - we need to create first. |
180 | | - |
181 | | - @Code(name: "Console", file: "route-guide-sec03-step02-mkdir.txt") |
182 | | - } |
183 | | - |
184 | | - @Step { |
185 | | - Now run `protoc` to generate the messages. This will create |
186 | | - `Sources/Generated/route_guide.pb.swift`. |
187 | | - |
188 | | - @Code(name: "Console", file: "route-guide-sec03-step03-gen-messages.txt") |
189 | | - } |
190 | | - |
191 | | - @Step { |
192 | | - Run `protoc` again to generate the service code. This will create |
193 | | - `Sources/Generated/route_guide.grpc.swift`. |
| 208 | + Build the project using `PROTOC_PATH=$(which protoc) swift build`. |
194 | 209 |
|
195 | | - @Code(name: "Console", file: "route-guide-sec03-step04-gen-grpc.txt") |
| 210 | + If you are using Xcode or another IDE then you'll need to set the environment variable |
| 211 | + appropriately. |
196 | 212 | } |
197 | 213 | } |
198 | 214 | } |
|
464 | 480 |
|
465 | 481 | @Steps { |
466 | 482 | @Step { |
467 | | - In one terminal run `swift run RouteGuide --server` to start the server. |
| 483 | + In one terminal run `PROTOC_PATH=$(which protoc) swift run RouteGuide --server` to start the server. |
468 | 484 |
|
469 | 485 | @Code(name: "Console", file: "route-guide-sec07-step01-server.txt") |
470 | 486 | } |
471 | 487 |
|
472 | 488 | @Step { |
473 | | - In another terminal run `swift run RouteGuide` to run the client program. |
| 489 | + In another terminal run `PROTOC_PATH=$(which protoc) swift run RouteGuide` to run the client program. |
474 | 490 |
|
475 | 491 | @Code(name: "Console", file: "route-guide-sec07-step02-client.txt") |
476 | 492 | } |
|
0 commit comments