Skip to content

Commit

Permalink
Update tutorials to use the build plugin (#2178)
Browse files Browse the repository at this point in the history
Motivation:

The examples have been updated to use the build plugin; so too should
the tutorials.

Modifications:

Update tutorials to use the build plugin.

Result:

Better tutorials.
  • Loading branch information
glbrntt authored Jan 24, 2025
1 parent f7261ad commit 4c6357d
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,28 @@
@Section(title: "Run a gRPC application") {
Let's start by running the existing Greeter application.

As a prerequisite you must have the Protocol Buffers compiler (`protoc`) installed. You can
find the instructions for doing this in the [gRPC Swift Protobuf
documentation](https://swiftpackageindex.com/grpc/grpc-swift-protobuf/documentation/grpcprotobuf/installing-protoc).
The remainder of this tutorial assumes you installed `protoc` and it's available in
your `$PATH`.

You may notice that the `swift` commands are all prefixed with `PROTOC_PATH=$(which protoc)`,
this is to let the build system know where `protoc` is located so that it can generate stubs
for you. You can read more about it in the [gRPC Swift Protobuf
documentation](https://swiftpackageindex.com/grpc/grpc-swift-protobuf/documentation/grpcprotobuf/generating-stubs).

@Steps {
@Step {
In a terminal run `swift run hello-world serve` to start the server. By default it'll start
listening on port 31415.
In a terminal run `PROTOC_PATH=$(which protoc) swift run hello-world serve` to start the
server. By default it'll start listening on port 31415.

@Code(name: "Console.txt", file: "hello-world-sec02-step01.txt")
}

@Step {
In another terminal run `swift run hello-world greet` to create a client, connect
to the server you started and send it a request and print the response.
In another terminal run `PROTOC_PATH=$(which protoc) swift run hello-world greet` to create
a client, connect to the server you started and send it a request and print the response.

@Code(name: "Console.txt", file: "hello-world-sec02-step02.txt")
}
Expand Down Expand Up @@ -75,19 +86,19 @@
}

@Section(title: "Update and run the application") {
You need to regenerate the stubs as the service definition has changed. To do this run the
following command from the _root of the checked out repository_:

```console
dev/protos/generate.sh
```
You need to regenerate the stubs as the service definition has changed. As you're using
the Swift Package Manager Build Plugin for gRPC Swift the gRPC code is automatically
generated if necessary when you build the example. You can learn more about generating stubs in
the <doc:Generating-stubs> article.

To learn how to generate stubs check out the <doc:Generating-stubs> article.

Now that the stubs have been updated you need to implement and call the new method in the
human-written parts of your application.

@Steps {
@Step {
Run `PROTOC_PATH=$(which protoc) swift build` to build the example. This will fail
because the service no longer implements all of the methods declared in the `.proto` file.
Let's fix that!
}

@Step {
Open `Serve.swift` in the `Subcommands` directory.

Expand All @@ -114,13 +125,14 @@

@Step {
Just like we did before, open a terminal and start the server by
running `swift run hello-world serve`
running `PROTOC_PATH=$(which protoc) swift run hello-world serve`

@Code(name: "Console.txt", file: "hello-world-sec04-step05.txt")
}

@Step {
In a separate terminal run `swift run hello-world greet` to call the server.
In a separate terminal run `PROTOC_PATH=$(which protoc) swift run hello-world greet` to
call the server.

@Code(name: "Console.txt", file: "hello-world-sec04-step06.txt")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// swift-tools-version: 6.0
import PackageDescription

let package = Package(
name: "RouteGuide",
platforms: [.macOS(.v15)],
dependencies: [
.package(url: "https://github.com/grpc/grpc-swift.git", from: "2.0.0-beta.3"),
.package(url: "https://github.com/grpc/grpc-swift-protobuf.git", from: "1.0.0-beta.3"),
.package(url: "https://github.com/grpc/grpc-swift-nio-transport.git", from: "1.0.0-beta.3"),
],
targets: [
.executableTarget(
name: "RouteGuide",
dependencies: [
.product(name: "GRPCCore", package: "grpc-swift"),
.product(name: "GRPCNIOTransportHTTP2", package: "grpc-swift-nio-transport"),
.product(name: "GRPCProtobuf", package: "grpc-swift-protobuf"),
],
plugins: [
.plugin(name: "GRPCProtobufGenerator", package: "grpc-swift-protobuf")
]
)
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"generate": {
"clients": true,
"servers": true,
"messages": true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/grpc/grpc-swift.git", from: "2.0.0-beta.3"),
.package(url: "https://github.com/grpc/grpc-swift-protobuf.git", from: "1.0.0-beta.3"),
.package(url: "https://github.com/grpc/grpc-swift-nio-transport.git", from: "1.0.0-beta.3"),
],
targets: [
.executableTarget(
Expand All @@ -15,6 +16,9 @@ let package = Package(
.product(name: "GRPCCore", package: "grpc-swift"),
.product(name: "GRPCNIOTransportHTTP2", package: "grpc-swift-nio-transport"),
.product(name: "GRPCProtobuf", package: "grpc-swift-protobuf"),
],
plugins: [
.plugin(name: "GRPCProtobufGenerator", package: "grpc-swift-protobuf")
]
)
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ let package = Package(
],
resources: [
.copy("route_guide_db.json")
],
plugins: [
.plugin(name: "GRPCProtobufGenerator", package: "grpc-swift-protobuf")
]
)
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ let package = Package(
],
resources: [
.copy("route_guide_db.json")
],
plugins: [
.plugin(name: "GRPCProtobufGenerator", package: "grpc-swift-protobuf")
]
)
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@
Before we can write any code we need to create a new Swift Package and configure it
to depend on gRPC Swift.

As a prerequisite you must have the Protocol Buffers compiler (`protoc`) installed. You can
find the instructions for doing this in the [gRPC Swift Protobuf
documentation](https://swiftpackageindex.com/grpc/grpc-swift-protobuf/documentation/grpcprotobuf/installing-protoc).
The remainder of this tutorial assumes you installed `protoc` and it's available in
your `$PATH`.

You may notice that the `swift` commands are all prefixed with `PROTOC_PATH=$(which protoc)`,
this is to let the build system know where `protoc` is located so that it can generate stubs
for you. You can read more about it in the [gRPC Swift Protobuf
documentation](https://swiftpackageindex.com/grpc/grpc-swift-protobuf/documentation/grpcprotobuf/generating-stubs).

@Steps {
@Step {
Create a new directory called for the package called `RouteGuide`.
Expand Down Expand Up @@ -84,6 +95,24 @@

@Code(name: "Package.swift", file: "route-guide-sec01-step08-description.swift")
}

@Step {
We'll also add a build plugin. This allows the build system to generate gRPC code at build
time rather than having to generate it with separate tooling.

@Code(name: "Package.swift", file: "route-guide-sec01-step09-plugin.swift")
}

@Step {
A configuration file is required so that the plugin knows what to generate. Create
a JSON file in the `Sources/Protos` directory called `grpc-swift-proto-generator-config.json`
with this content.

The name of the file (`grpc-swift-proto-generator-config.json`) is important: the plugin
looks for files matching this name in the source directory of your target.

@Code(name: "Sources/Protos/grpc-swift-proto-generator-config.json", file: "route-guide-sec01-step10-plugin-config.json")
}
}
}

Expand All @@ -93,16 +122,26 @@

@Steps {
@Step {
Create a new empty file in the `Protos` directory called `route_guide.proto`. We'll use
the "proto3" syntax and our service will be part of the "routeguide" package.
Create a new directory in the `Sources/Protos` directory called `routeguide`
using `mkdir Sources/Protos/routeguide`.
}

@Step {
Create a new empty file in the `Sources/Protos/routeguide` directory
called `route_guide.proto`. We'll use the "proto3" syntax and our service will be part of
the "routeguide" package.

@Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step01-import.proto")
It's good practice to organize your `.proto` files according to the package they are
declared in, that's why we created the `routeguide` directory to match the "routeguide"
package name.

@Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step01-import.proto")
}

@Step {
To define a service we create a named `service` in the `.proto` file.

@Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step02-service.proto")
@Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step02-service.proto")
}

@Step {
Expand All @@ -113,7 +152,7 @@
A *unary RPC* where the client sends a request to the server using the stub
and waits for a response to come back, just like a normal function call.

@Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step03-unary.proto")
@Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step03-unary.proto")
}

@Step {
Expand All @@ -123,7 +162,7 @@
example, you specify a server-side streaming method by placing the `stream`
keyword before the *response* type.

@Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step04-server-streaming.proto")
@Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step04-server-streaming.proto")
}

@Step {
Expand All @@ -133,7 +172,7 @@
and return its response. You specify a client-side streaming method by placing
the `stream` keyword before the *request* type.

@Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step05-client-streaming.proto")
@Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step05-client-streaming.proto")
}

@Step {
Expand All @@ -146,53 +185,30 @@
stream is preserved. You specify this type of method by placing the `stream`
keyword before both the request and the response.

@Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step06-bidi-streaming.proto")
@Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step06-bidi-streaming.proto")
}

@Step {
The `.proto` file also contains the Protocol Buffers message type definitions for all
request and response messages used by the service.

@Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step07-messages.proto")
@Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step07-messages.proto")
}
}
}

@Section(title: "Generating client and server code") {
Next we need to generate the gRPC client and server interfaces from our `.proto`
service definition. We do this using the Protocol Buffer compiler, `protoc`, with
two plugins: one with support for Swift (via [Swift Protobuf](https://github.com/apple/swift-protobuf))
and the other for gRPC. This section assumes you already have `protoc` installed.
service definition. As we're using the build plugin we just need to build our project.

To learn more about generating code check out the <doc:Generating-stubs> article.

@Steps {
@Step {
First we need to build the two plugins for `protoc`, `protoc-gen-swift` and
`protoc-gen-grpc-swift`.

@Code(name: "Console", file: "route-guide-sec03-step01-protoc-plugins.txt")
}

@Step {
We'll generate the code into a separate directory within `Sources` called `Generated` which
we need to create first.

@Code(name: "Console", file: "route-guide-sec03-step02-mkdir.txt")
}

@Step {
Now run `protoc` to generate the messages. This will create
`Sources/Generated/route_guide.pb.swift`.

@Code(name: "Console", file: "route-guide-sec03-step03-gen-messages.txt")
}

@Step {
Run `protoc` again to generate the service code. This will create
`Sources/Generated/route_guide.grpc.swift`.
Build the project using `PROTOC_PATH=$(which protoc) swift build`.

@Code(name: "Console", file: "route-guide-sec03-step04-gen-grpc.txt")
If you are using Xcode or another IDE then you'll need to set the environment variable
appropriately.
}
}
}
Expand Down Expand Up @@ -464,13 +480,13 @@

@Steps {
@Step {
In one terminal run `swift run RouteGuide --server` to start the server.
In one terminal run `PROTOC_PATH=$(which protoc) swift run RouteGuide --server` to start the server.

@Code(name: "Console", file: "route-guide-sec07-step01-server.txt")
}

@Step {
In another terminal run `swift run RouteGuide` to run the client program.
In another terminal run `PROTOC_PATH=$(which protoc) swift run RouteGuide` to run the client program.

@Code(name: "Console", file: "route-guide-sec07-step02-client.txt")
}
Expand Down

0 comments on commit 4c6357d

Please sign in to comment.