-
Notifications
You must be signed in to change notification settings - Fork 420
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Created README for the Reflection Service (#1694)
Motivation: To help users set up a Server that is implementing the Reflection Service. Modifications: Added a step by step tutorial on how to set up the example server and run GRPCurl in order to test the Reflection Service. Result: Users will get information on how to set up the Reflection Service for a Server.
- Loading branch information
1 parent
187b609
commit 7ea3260
Showing
8 changed files
with
316 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
Sources/Examples/ReflectionService/Generated/echo.grpc.reflection.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
CgplY2hvLnByb3RvEgRlY2hvIiEKC0VjaG9SZXF1ZXN0EhIKBHRleHQYASABKAlSBHRleHQiIgoMRWNob1Jlc3BvbnNlEhIKBHRleHQYASABKAlSBHRleHQy2AEKBEVjaG8SLgoDR2V0EhEuZWNoby5FY2hvUmVxdWVzdBoSLmVjaG8uRWNob1Jlc3BvbnNlIgASMwoGRXhwYW5kEhEuZWNoby5FY2hvUmVxdWVzdBoSLmVjaG8uRWNob1Jlc3BvbnNlIgAwARI0CgdDb2xsZWN0EhEuZWNoby5FY2hvUmVxdWVzdBoSLmVjaG8uRWNob1Jlc3BvbnNlIgAoARI1CgZVcGRhdGUSES5lY2hvLkVjaG9SZXF1ZXN0GhIuZWNoby5FY2hvUmVzcG9uc2UiACgBMAFK/QoKBhIEDgAoAQrCBAoBDBIDDgASMrcEIENvcHlyaWdodCAoYykgMjAxNSwgR29vZ2xlIEluYy4KCiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKCiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCggKAQISAxAADQoKCgIGABIEEgAeAQoKCgMGAAESAxIIDAo4CgQGAAIAEgMUAjAaKyBJbW1lZGlhdGVseSByZXR1cm5zIGFuIGVjaG8gb2YgYSByZXF1ZXN0LgoKDAoFBgACAAESAxQGCQoMCgUGAAIAAhIDFAoVCgwKBQYAAgADEgMUICwKWQoEBgACARIDFwI6GkwgU3BsaXRzIGEgcmVxdWVzdCBpbnRvIHdvcmRzIGFuZCByZXR1cm5zIGVhY2ggd29yZCBpbiBhIHN0cmVhbSBvZiBtZXNzYWdlcy4KCgwKBQYAAgEBEgMXBgwKDAoFBgACAQISAxcNGAoMCgUGAAIBBhIDFyMpCgwKBQYAAgEDEgMXKjYKYgoEBgACAhIDGgI7GlUgQ29sbGVjdHMgYSBzdHJlYW0gb2YgbWVzc2FnZXMgYW5kIHJldHVybnMgdGhlbSBjb25jYXRlbmF0ZWQgd2hlbiB0aGUgY2FsbGVyIGNsb3Nlcy4KCgwKBQYAAgIBEgMaBg0KDAoFBgACAgUSAxoOFAoMCgUGAAICAhIDGhUgCgwKBQYAAgIDEgMaKzcKTQoEBgACAxIDHQJBGkAgU3RyZWFtcyBiYWNrIG1lc3NhZ2VzIGFzIHRoZXkgYXJlIHJlY2VpdmVkIGluIGFuIGlucHV0IHN0cmVhbS4KCgwKBQYAAgMBEgMdBgwKDAoFBgACAwUSAx0NEwoMCgUGAAIDAhIDHRQfCgwKBQYAAgMGEgMdKjAKDAoFBgACAwMSAx0xPQoKCgIEABIEIAAjAQoKCgMEAAESAyAIEwoyCgQEAAIAEgMiAhIaJSBUaGUgdGV4dCBvZiBhIG1lc3NhZ2UgdG8gYmUgZWNob2VkLgoKDAoFBAACAAUSAyICCAoMCgUEAAIAARIDIgkNCgwKBQQAAgADEgMiEBEKCgoCBAESBCUAKAEKCgoDBAEBEgMlCBQKLAoEBAECABIDJwISGh8gVGhlIHRleHQgb2YgYW4gZWNobyByZXNwb25zZS4KCgwKBQQBAgAFEgMnAggKDAoFBAECAAESAycJDQoMCgUEAQIAAxIDJxARYgZwcm90bzM= |
1 change: 1 addition & 0 deletions
1
Sources/Examples/ReflectionService/Generated/helloworld.grpc.reflection.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ChBoZWxsb3dvcmxkLnByb3RvEgpoZWxsb3dvcmxkIiIKDEhlbGxvUmVxdWVzdBISCgRuYW1lGAEgASgJUgRuYW1lIiYKCkhlbGxvUmVwbHkSGAoHbWVzc2FnZRgBIAEoCVIHbWVzc2FnZTJJCgdHcmVldGVyEj4KCFNheUhlbGxvEhguaGVsbG93b3JsZC5IZWxsb1JlcXVlc3QaFi5oZWxsb3dvcmxkLkhlbGxvUmVwbHkiAEI2Chtpby5ncnBjLmV4YW1wbGVzLmhlbGxvd29ybGRCD0hlbGxvV29ybGRQcm90b1ABogIDSExXSrMICgYSBA4AJQEKvwQKAQwSAw4AEjK0BCBDb3B5cmlnaHQgMjAxNSBnUlBDIGF1dGhvcnMuCgogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKCiAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCgoICgEIEgMQACIKCQoCCAoSAxAAIgoICgEIEgMRADQKCQoCCAESAxEANAoICgEIEgMSADAKCQoCCAgSAxIAMAoICgEIEgMTACEKCQoCCCQSAxMAIQoICgECEgMVABMKLgoCBgASBBgAGwEaIiBUaGUgZ3JlZXRpbmcgc2VydmljZSBkZWZpbml0aW9uLgoKCgoDBgABEgMYCA8KIAoEBgACABIDGgI1GhMgU2VuZHMgYSBncmVldGluZy4KCgwKBQYAAgABEgMaBg4KDAoFBgACAAISAxoQHAoMCgUGAAIAAxIDGicxCj0KAgQAEgQeACABGjEgVGhlIHJlcXVlc3QgbWVzc2FnZSBjb250YWluaW5nIHRoZSB1c2VyJ3MgbmFtZS4KCgoKAwQAARIDHggUCgsKBAQAAgASAx8CEgoMCgUEAAIABRIDHwIICgwKBQQAAgABEgMfCQ0KDAoFBAACAAMSAx8QEQo8CgIEARIEIwAlARowIFRoZSByZXNwb25zZSBtZXNzYWdlIGNvbnRhaW5pbmcgdGhlIGdyZWV0aW5ncy4KCgoKAwQBARIDIwgSCgsKBAQBAgASAyQCFQoMCgUEAQIABRIDJAIICgwKBQQBAgABEgMkCRAKDAoFBAECAAMSAyQTFGIGcHJvdG8z |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../HelloWorld/Server/GreeterProvider.swift |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* Copyright 2023, gRPC Authors All rights reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import ArgumentParser | ||
import EchoImplementation | ||
import EchoModel | ||
import Foundation | ||
import GRPC | ||
import GRPCReflectionService | ||
import NIOPosix | ||
import SwiftProtobuf | ||
|
||
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) | ||
@main | ||
struct ReflectionServer: AsyncParsableCommand { | ||
func run() async throws { | ||
// Getting the URLs of the files containing the reflection data. | ||
guard | ||
let greeterURL = Bundle.module.url( | ||
forResource: "helloworld", | ||
withExtension: "grpc.reflection.txt" | ||
), | ||
let echoURL = Bundle.module.url(forResource: "echo", withExtension: "grpc.reflection.txt") | ||
else { | ||
print("The resource could not be loaded.") | ||
throw ExitCode.failure | ||
} | ||
|
||
let reflectionService = try ReflectionService( | ||
reflectionDataFileURLs: [greeterURL, echoURL], | ||
version: .v1 | ||
) | ||
|
||
// Start the server and print its address once it has started. | ||
let server = try await Server.insecure(group: MultiThreadedEventLoopGroup.singleton) | ||
.withServiceProviders([reflectionService, GreeterProvider(), EchoProvider()]) | ||
.bind(host: "localhost", port: 1234) | ||
.get() | ||
|
||
print("server started on port \(server.channel.localAddress!.port!)") | ||
// Wait on the server's `onClose` future to stop the program from exiting. | ||
try await server.onClose.get() | ||
} | ||
} |
189 changes: 189 additions & 0 deletions
189
Sources/GRPCReflectionService/Documentation.docc/ReflectionServiceTutorial.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
# Reflection service | ||
|
||
This tutorial goes through the steps of adding Reflection service to a | ||
server, running it and testing it using gRPCurl. | ||
|
||
The server used in this example is implemented at | ||
[Sources/Examples/ReflectionService/ReflectionServer.swift][reflection-server] | ||
and it supports the "Greeter", "Echo", and "Reflection" services. | ||
|
||
|
||
## Overview | ||
|
||
The Reflection service provides information about the public RPCs served by a server. | ||
It is specific to services defined using the Protocol Buffers IDL. | ||
By calling the Reflection service, clients can construct and send requests to services | ||
without needing to generate code and types for them. | ||
|
||
You can also use CLI clients such as [gRPCurl][grpcurl-setup] and the [gRPC command line tool][grpc-cli] to: | ||
- list services, | ||
- describe services and their methods, | ||
- describe symbols, | ||
- describe extensions, | ||
- construct and invoke RPCs. | ||
|
||
gRPC Swift supports both [v1][v1] and [v1alpha][v1alpha] of the reflection service. | ||
|
||
## Adding the Reflection service to a server | ||
|
||
You can use the Reflection service by adding it as a provider when constructing your server. | ||
|
||
To initialise the Reflection service we will use | ||
``GRPCReflectionService/ReflectionService/init(reflectionDataFileURLs:version:)``. | ||
It receives the URLs of the files containing the reflection data of the proto files | ||
describing the services of the server and the version of the reflection service. | ||
|
||
### Generating the reflection data | ||
|
||
The server from this example uses the `GreeterProvider` and the `EchoProvider`, | ||
besides the `ReflectionService`. | ||
|
||
The associated proto files are located at `Sources/Examples/HelloWorld/Model/helloworld.proto`, and | ||
`Sources/Examples/Echo/Model/echo.proto` respectively. | ||
|
||
In order to generate the reflection data for the `helloworld.proto`, you can run the following command: | ||
|
||
```sh | ||
$ protoc Sources/Examples/HelloWorld/Model/helloworld.proto \ | ||
--proto_path=Sources/Examples/HelloWorld/Model \ | ||
--grpc-swift_opt=Client=false,Server=false,ReflectionData=true \ | ||
--grpc-swift_out=Sources/Examples/ReflectionService/Generated | ||
``` | ||
|
||
Let's break the command down: | ||
- The first argument passed to `protoc` is the path | ||
to the `.proto` file to generate reflection data | ||
for: [`Sources/Examples/HelloWorld/Model/helloworld.proto`][helloworld-proto]. | ||
- The `proto_path` flag is the path to search for imports: `Sources/Examples/HelloWorld/Model`. | ||
- The 'grpc-swift_opt' flag allows us to list options for the Swift generator. | ||
To generate only the reflection data set: `Client=false,Server=false,ReflectionData=true`. | ||
- The `grpc-swift_out` flag is used to set the path of the directory | ||
where the generated file will be located: `Sources/Examples/ReflectionService/Generated`. | ||
|
||
This command assumes that the `protoc-gen-grpc-swift` plugin is in your `$PATH` environment variable. | ||
You can learn how to get the plugin from this section of the `grpc-swift` README: | ||
https://github.com/grpc/grpc-swift#getting-the-protoc-plugins. | ||
|
||
The command for generating the reflection data for the `Echo` service is similar. | ||
|
||
You can use Swift Package Manager [resources][swiftpm-resources] to add the generated reflection data to your target. | ||
In our example the reflection data is written into the "Generated" directory within the target | ||
so we include the `.copy("Generated")` rule in our target's resource list. | ||
|
||
### Instantiating the Reflection service | ||
|
||
To instantiate the `ReflectionService` you need to pass the URLs of the files containing | ||
the generated reflection data and the version to use, in our case `.v1`. | ||
|
||
Depending on the version of [gRPCurl][grpcurl] you are using you might need to use the `.v1alpha` instead. | ||
Beginning with [gRPCurl v1.8.8][grpcurl-v188] it uses the [v1][v1] reflection. Earlier versions use [v1alpha][v1alpha] | ||
reflection. | ||
|
||
```swift | ||
// Getting the URLs of the files containing the reflection data. | ||
guard | ||
let greeterURL = Bundle.module.url( | ||
forResource: "helloworld", | ||
withExtension: "grpc.reflection.txt" | ||
), | ||
let echoURL = Bundle.module.url(forResource: "echo", withExtension: "grpc.reflection.txt") | ||
else { | ||
print("The resource could not be loaded.") | ||
throw ExitCode.failure | ||
} | ||
let reflectionService = try ReflectionService( | ||
reflectionDataFileURLs: [greeterURL, echoURL], | ||
version: .v1 | ||
) | ||
``` | ||
|
||
### Running the server | ||
|
||
In our example the server isn't configured with TLS and listens on localhost port 1234. | ||
The following code configures and starts the server: | ||
|
||
```swift | ||
let server = try await Server.insecure(group: group) | ||
.withServiceProviders([reflectionService, GreeterProvider(), EchoProvider()]) | ||
.bind(host: "localhost", port: self.port) | ||
.get() | ||
|
||
``` | ||
|
||
To run the server, from the root of the package run: | ||
|
||
```sh | ||
$ swift run ReflectionServer | ||
``` | ||
|
||
## Calling the Reflection service with gRPCurl | ||
|
||
Please follow the instructions from the [gRPCurl README][grpcurl-setup] to set up gRPCurl. | ||
|
||
From a different terminal than the one used for running the server, we will call gRPCurl commands, | ||
following the format: `grpcurl [flags] [address] [list|describe] [symbol]`. | ||
|
||
We use the `-plaintext` flag, because the server isn't configured with TLS, and | ||
the address is set to `localhost:1234`. | ||
|
||
|
||
To see the available services use `list`: | ||
|
||
```sh | ||
$ grpcurl -plaintext localhost:1234 list | ||
echo.Echo | ||
helloworld.Greeter | ||
``` | ||
|
||
To see what methods are available for a service: | ||
|
||
```sh | ||
$ grpcurl -plaintext localhost:1234 list echo.Echo | ||
echo.Echo.Collect | ||
echo.Echo.Expand | ||
echo.Echo.Get | ||
echo.Echo.Update | ||
``` | ||
|
||
You can also get descriptions of objects like services, methods, and messages. The following | ||
command fetches a description of the Echo service: | ||
|
||
```sh | ||
$ grpcurl -plaintext localhost:1234 describe echo.Echo | ||
echo.Echo is a service: | ||
service Echo { | ||
// Collects a stream of messages and returns them concatenated when the caller closes. | ||
rpc Collect ( stream .echo.EchoRequest ) returns ( .echo.EchoResponse ); | ||
// Splits a request into words and returns each word in a stream of messages. | ||
rpc Expand ( .echo.EchoRequest ) returns ( stream .echo.EchoResponse ); | ||
// Immediately returns an echo of a request. | ||
rpc Get ( .echo.EchoRequest ) returns ( .echo.EchoResponse ); | ||
// Streams back messages as they are received in an input stream. | ||
rpc Update ( stream .echo.EchoRequest ) returns ( stream .echo.EchoResponse ); | ||
} | ||
``` | ||
|
||
You can send requests to the services with gRPCurl: | ||
|
||
```sh | ||
$ grpcurl -d '{ "text": "test" }' -plaintext localhost:1234 echo.Echo.Get | ||
{ | ||
"text": "Swift echo get: test" | ||
} | ||
``` | ||
|
||
Note that when specifying a service, a method or a symbol, we have to use the fully qualified names: | ||
- service: \<package\>.\<service\> | ||
- method: \<package\>.\<service\>.\<method\> | ||
- type: \<package\>.\<type\> | ||
|
||
[grpcurl-setup]: https://github.com/fullstorydev/grpcurl#grpcurl | ||
[grpcurl]: https://github.com/fullstorydev/grpcurl | ||
[grpc-cli]: https://github.com/grpc/grpc/blob/master/doc/command_line_tool.md | ||
[v1]: ../v1/reflection-v1.proto | ||
[v1alpha]: ../v1Alpha/reflection-v1alpha.proto | ||
[reflection-server]: ../../Examples/ReflectionService/ReflectionServer.swift | ||
[helloworld-proto]: ../../Examples/HelloWorld/Model/helloworld.proto | ||
[echo-proto]: ../../Examples/Echo/Model/echo.proto | ||
[grpcurl-v188]: https://github.com/fullstorydev/grpcurl/releases/tag/v1.8.8 | ||
[swiftpm-resources]: https://github.com/apple/swift-package-manager/blob/main/Documentation/PackageDescription.md#resource |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters