• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1GRPC Server Reflection Protocol
2===============================
3
4This document describes server reflection as an optional extension for servers
5to assist clients in runtime construction of requests without having stub
6information precompiled into the client.
7
8The primary usecase for server reflection is to write (typically) command line
9debugging tools for talking to a grpc server. In particular, such a tool will
10take in a method and a payload (in human readable text format) send it to the
11server (typically in binary proto wire format), and then take the response and
12decode it to text to present to the user.
13
14This broadly involves two problems: determining what formats (which protobuf
15messages) a server’s method uses, and determining how to convert messages
16between human readable format and the (likely binary) wire format.
17
18## Method reflection
19
20We want to be able to answer the following queries:
21 1. What methods does a server export?
22 2. For a particular method, how do we call it?
23Specifically, what are the names of the methods, are those methods unary or
24streaming, and what are the types of the argument and result?
25
26```
27#TODO(dklempner): link to an actual .proto later.
28package grpc.reflection.v1alpha;
29
30message ListApisRequest {
31}
32
33message ListApisResponse {
34  repeated google.protobuf.Api apis = 1;
35}
36
37message GetMethodRequest {
38  string method = 1;
39}
40message GetMethodResponse {
41  google.protobuf.Method method = 1;
42}
43
44service ServerReflection {
45  rpc ListApis (ListApisRequest) returns (ListApisResponse);
46  rpc GetMethod (GetMethodRequest) returns (GetMethodResponse);
47}
48```
49
50Note that a server is under no obligation to return a complete list of all
51methods it supports. For example, a reverse proxy may support server reflection
52for methods implemented directly on the proxy but not enumerate all methods
53supported by its backends.
54
55
56### Open questions on method reflection
57 * Consider how to extend this protocol to support non-protobuf methods.
58
59## Argument reflection
60The second half of the problem is converting between the human readable
61input/output of a debugging tool and the binary format understood by the
62method.
63
64This is obviously dependent on protocol type. At one extreme, if both the
65server and the debugging tool accept JSON, there may be no need for such a
66conversion in the first place. At the opposite extreme, a server using a custom
67binary format has no hope of being supported by a generic system. The
68intermediate interesting common case is a server which speaks binary-proto and
69a debugging client which speaks either ascii-proto or json-proto.
70
71One approach would be to require servers directly support human readable input.
72In the future method reflection may be extended to document such support,
73should it become widespread or standardized.
74
75## Protobuf descriptors
76
77A second would be for the server to export its
78google::protobuf::DescriptorDatabase over the wire. This is very easy to
79implement in C++, and Google implementations of a similar protocol already
80exist in C++, Go, and Java.
81
82This protocol mostly returns FileDescriptorProtos, which are a proto encoding
83of a parsed .proto file. It supports four queries:
84 1. The FileDescriptorProto for a given file name
85 2. The FileDescriptorProto for the file with a given symbol
86 3. The FileDescriptorProto for the file with a given extension
87 4. The list of known extension tag numbers of a given type
88
89These directly correspond to the methods of
90google::protobuf::DescriptorDatabase. Note that this protocol includes support
91for extensions, which have been removed from proto3 but are still in widespread
92use in Google’s codebase.
93
94Because most usecases will require also requesting the transitive dependencies
95of requested files, the queries will also return all transitive dependencies of
96the returned file. Should interesting usecases for non-transitive queries turn
97up later, we can easily extend the protocol to support them.
98
99### Reverse proxy traversal
100
101One potential issue with naive reverse proxies is that, while any individual
102server will have a consistent and valid picture of the proto DB which is
103sufficient to handle incoming requests, incompatibilities will arise if the
104backend servers have a mix of builds. For example, if a given message is moved
105from foo.proto to bar.proto, and the client requests foo.proto from an old
106server and bar.proto from a new server, the resulting database will have a
107double definition.
108
109To solve this problem, the protocol is structured as a bidirectional stream,
110ensuring all related requests go to a single server. This has the additional
111benefit that overlapping recursive requests don’t require sending a lot of
112redundant information, because there is a single stream to maintain context
113between queries.
114
115```
116package grpc.reflection.v1alpha;
117message DescriptorDatabaseRequest {
118  string host = 1;
119  oneof message_request {
120    string files_for_file_name = 3;
121    string files_for_symbol_name = 4;
122    FileContainingExtensionRequest file_containing_extension = 5;
123    string list_all_extensions_of_type = 6;
124  }
125}
126
127message FileContainingExtensionRequest {
128  string base_message = 1;
129  int64 extension_id = 2;
130}
131
132message DescriptorDatabaseResponse {
133  string valid_host = 1;
134  DescriptorDatabaseRequest original_request = 2;
135  oneof message_response {
136    // These are proto2 type google.protobuf.FileDescriptorProto, but
137    // we avoid taking a dependency on descriptor.proto, which uses
138    // proto2 only features, by making them opaque
139    // bytes instead
140    repeated bytes fd_proto = 4;
141    ListAllExtensionsResponse extensions_response = 5;
142    // Notably includes error code 5, NOT FOUND
143    int32 error_code = 6;
144  }
145}
146
147message ListAllExtensionsResponse {
148  string base_type_name;
149  repeated int64 extension_number;
150}
151
152service ProtoDescriptorDatabase {
153  rpc DescriptorDatabaseInfo(stream DescriptorDatabaseRequest) returns (stream DescriptorDatabaseResponse);
154}
155```
156
157Any given request must either result in an error code or an answer, usually in
158the form of a  series of FileDescriptorProtos with the requested file itself
159and all previously unsent transitive imports of that file. Servers may track
160which FileDescriptorProtos have been sent on a given stream, for a given value
161of valid_host, and avoid sending them repeatedly for overlapping requests.
162
163| message_request message     | Result                                          |
164| files_for_file_name         | transitive closure of file name                 |
165| files_for_symbol_name       | transitive closure file containing symbol       |
166| file_containing_extension   | transitive closure of file containing a given extension number of a given symbol |
167| list_all_extensions_of_type | ListAllExtensionsResponse containing all known extension numbers of a given type |
168
169At some point it would make sense to additionally also support any.proto’s
170format. Note that known any.proto messages can be queried by symbol using this
171protocol even without any such support, by parsing the url and extracting the
172symbol name from it.
173
174## Language specific implementation thoughts
175All of the information needed to implement Proto reflection is available to the
176code generator, but I’m not certain we actually generate this in every
177language. If the proto implementation in the  language doesn’t have something
178like google::protobuf::DescriptorPool the grpc implementation for that language
179will need to index those FileDescriptorProtos by file and symbol and imports.
180
181One issue is that some grpc implementations are very loosely coupled with
182protobufs; in such implementations it probably makes sense to split apart these
183reflection APIs so as not to take an additional proto dependency.
184
185## Known Implementations
186
187Enabling server reflection differs language-to-language. Here are links to docs relevant to
188each language:
189
190- [Java](https://github.com/grpc/grpc-java/blob/master/documentation/server-reflection-tutorial.md#enable-server-reflection)
191- [Go](https://github.com/grpc/grpc-go/blob/master/Documentation/server-reflection-tutorial.md#enable-server-reflection)
192- [C++](https://grpc.io/grpc/cpp/md_doc_server_reflection_tutorial.html)
193- [C#](https://github.com/grpc/grpc/blob/master/doc/csharp/server_reflection.md)
194- [Python](https://github.com/grpc/grpc/blob/master/doc/python/server_reflection.md)
195- Ruby: not yet implemented [#2567](https://github.com/grpc/grpc/issues/2567)
196- Node: not yet implemented [#2568](https://github.com/grpc/grpc/issues/2568)
197