trpc.group/trpc-go/trpc-go@v1.0.3/docs/basics_tutorial.md (about) 1 English | [中文](./basics_tutorial.zh_CN.md) 2 3 ## Basics Tutorial 4 5 In [Quick Start](./quick_start.md), you have successfully run tRPC-Go helloworld. However, we ignore many details. In this chapter, you will understand the tRPC-Go service development process in more detail. We will introduce in turn: 6 - How to define tRPC service by protobuf? 7 - How to configure `trpc_go.yaml`? 8 - What extension capabilities does tRPC-Go have? 9 - Various features supported by tRPC-Go. 10 11 Our service definition depends on Protocol Buffer v3. You can refer to [Official Documents of Golang Protobuf](https://protobuf.dev/getting-started/gotutorial/). 12 13 ### Define Service 14 15 To define a new service, we need to declare it in protobuf first. The following example defines a service named `MyService`: 16 ```protobuf 17 service MyService { 18 // ... 19 } 20 ``` 21 22 A service may have many methods which are defined inside service body. In following example, we define a method `Hello` for service `Greeter`. The `Hello` use `HelloReq` as its parameter and returns `HelloRsp`. 23 ```protobuf 24 service Greeter { 25 rpc Hello(HelloReq) returns (HelloRsp) {} 26 // ... 27 } 28 29 message HelloReq { 30 // ... 31 } 32 33 message HelloRsp { 34 // ... 35 } 36 ``` 37 38 Note that `Method` has a `{}` at the end, which can also have content. We will see later. 39 40 ### Write Client and Server Code 41 42 What protobuf gives is a language-independent service definition, and we need to use [trpc command line tool](https://github.com/trpc-group/trpc-cmdline) to translate it into a corresponding language stub code. You can see the various options it supports with `$ trpc create -h`. You can refer to the quick start [helloworld](/examples/helloworld/pb/Makefile) project to quickly create your own stub code. 43 44 The stub code is mainly divided into two parts: client and server. 45 Below is part of the generated client code. In [Quick Start](./quick_start.md), we use `NewGreeterClientProxy` to create a client instance and call its `Hello` method: 46 ```go 47 type GreeterClientProxy interface { 48 Hello(ctx context.Context, req *HelloReq, opts ...client.Option) (rsp *HelloRsp, err error) 49 } 50 51 var NewGreeterClientProxy = func(opts ...client.Option) GreeterClientProxy { 52 return &GreeterClientProxyImpl{client: client.DefaultClient, opts: opts} 53 } 54 ``` 55 56 The following is part of the generated server code, `GreeterService` defines the interface you need to implement. `RegisterGreeterService` will register your implementation to the framework. In [Quick Start](./quick_start.md), we first create a tRPC-Go instance through `s := trpc.NewServer()`, and then register the `Greeter` structure that implements the business logic to `s`. 57 ```go 58 type GreeterService interface { 59 Hello(ctx context.Context, req *HelloReq) (*HelloRsp, error) 60 } 61 62 func RegisterGreeterService(s server.Service, svr GreeterService) { /* ... */ } 63 ``` 64 65 ### Configuration 66 67 Maybe you have noticed a little difference between client and server. On the client side, we specified the address of the server through `client.WithTarget`, but on the server side, we did not find the corresponding address in the code. In fact, it is configured in `./server/trpc_go.yaml`. 68 This is the yaml configuration capability supported by tRPC-Go. Almost all tRPC-Go framework capabilities can be customized through file configuration. When you execute tRPC-Go, the framework will look for the `trpc_go.yaml` file in the current directory and load the relevant configuration. This allows you to change the behavior of your application without recompiling the service. 69 Below are some necessary configurations required for this tutorial, please refer to [Framework Configuration](/docs/user_guide/framework_conf.md) for complete configurations. 70 ```yaml 71 server: 72 service: # you can config multiple services 73 - name: helloworld 74 ip: 127.0.0.1 75 port: 8000 76 protocol: trpc 77 ``` 78 79 ### Filter and Plugin 80 81 tRPC-Go has rich scalability, you can inject various new capabilities into the RPC process through filters, and the plugin factory allows you to easily integrate new functions. 82 83 #### Filter 84 85 [Filter](/filter) likes an onion. An RPC goes through each layer of the onion in turn. You can customize this onion model through Filters. 86 87 The client filter is defined as follows: 88 ```go 89 type ClientFilter func(ctx context.Context, req, rsp interface{}, next ClientHandleFunc) error 90 type ClientHandleFunc func(ctx context.Context, req, rsp interface{}) error 91 ``` 92 When implement your own filters: 93 ```go 94 func MyFilter(ctx context.Context, req, rsp interface{}, next ClientHandleFunc) error { 95 // pre-RPC processes 96 err := next(ctx, req, rsp) 97 // post-RPC processes 98 return err 99 } 100 ``` 101 Codes before and after `next` will be executed before and after the actual RPC, that is, pre-RPC processes and post-RPC processes. You can implement many filters, which are used when calling [`client.WithFilters`](/client/options.go). Framework Will automatically concat these filter into a chain. 102 103 The signature of server filter is slightly different from client: 104 ```go 105 type ServerFilter func(ctx context.Context, req interface{}, next ServerHandleFunc) (rsp interface{}, err error) 106 type ServerHandleFunc func(ctx context.Context, req interface{}) (rsp interface{}, err error) 107 ``` 108 `rsp` is in the return value, not the argument. Server filter should be injected into the framework by [`server.WithFilters`](/server/options.go). The framework will automatically concat these filters into a chain. 109 110 In addition to adding filters directly through code mentioned above, you can also load filters through configuration files. 111 ```yaml 112 client: 113 filter: # these are client global filters 114 - client_filter_name_1 115 - client_filter_name_2 116 service: 117 - name: xxx 118 filter: # these are special filters for service xxx, they will be appended to global filters. 119 - client_filter_name_3 120 server: 121 filter: # these are server global filters 122 - server_filter_name_1 123 - server_filter_name_2 124 service: 125 - name: yyy 126 filter: # these are special filters for service yyy, they will be appended to global filters. 127 - server_filter_name_3 128 ``` 129 These filters need to be registered in the framework in advance via [`filter.Register`](/filter/filter.go). They are automatically loaded by the framework when `trpc.NewServer` is executed. 130 Note that when the code and the configuration file exist at the same time, the interceptor specified by the code will be executed first, and then the interceptor specified by the configuration file. 131 132 You can see an example of filter usage [here](/examples/features/filter). 133 134 #### Plugin 135 136 [Plugin](/plugin) is an automatic module loading mechanism designed by tRPC-Go based on yaml configuration file. Its interface is defined as follows: 137 ```go 138 package plugin 139 140 type Factory interface { 141 Type() string 142 Setup(name string, dec Decoder) error 143 } 144 145 type Decoder interface { 146 Decode(cfg interface{}) error 147 } 148 ``` 149 `Type` returns the type of the plugin, and `Setup` will pass in the plugin name and a `Decoder` for parsing the content of yaml. The content of plugin is configured in `trpc_go.yaml`: 150 ```yaml 151 plugins: 152 __type: 153 __name: 154 # plugin contents 155 ``` 156 where `__type` should be replaced by the value returned by `Factory.Type()` and `__name` should be replaced by the first parameter of `plugin.Register`. 157 158 When implementing a `plugin`, you should create a `func init()` function to register your plugin via `Register`. In this way, when others use your plugin, they only need to import your package anonymously in the code. When `trpc.NewServer()` is called, the plugin will call the `Factory.Setup` function for initialization. 159 160 Plugins often cooperate with filters, such as calling `filter.Register` in the `Factory.Setup` function to register a filter. The framework guarantees that plugin initialization completes before filters are loaded. This way, you can configure the behavior of the filter by modifying plugin of `trpc_go.yaml`. 161 162 ### Other Supported Protocols 163 164 [Quick start](./quick_start.md) introduces a common one-request-one-response RPC. tRPC-Go also supports streaming RPC, HTTP, and more. 165 166 #### streaming RPC 167 168 Streaming RPC supports more flexible interactions between clients and servers. It can be divided into three modes: client-side streaming, server-side streaming, and bidirectional streaming. 169 Client streaming allows the client to send multiple packets in sequence, and the server returns a packet after receiving all of them. It is a many-to-one relationship. 170 Server-side streaming allows the server to generate multiple responses for a client request. It is a one-to-many relationship. 171 Bidirectional streaming allows the client and the server to send requests to each other in parallel, in order, just like two people in a conversation. It is a many-to-many relationship. 172 173 The code in this section is based on [`example/stream`](/examples/features/stream). 174 175 Unlike normal RPCs, declaring streaming RPCs in protobuf requires the use of the `stream` keyword. 176 ```protobuf 177 service TestStream { 178 rpc ClientStream (stream HelloReq) returns (HelloRsp); 179 rpc ServerStream (HelloReq) returns (stream HelloRsp); 180 rpc BidirectionalStream (stream HelloReq) returns (stream HelloRsp); 181 } 182 ``` 183 When `stream` only appears before the method request, the method is client-side streaming; when `stream` only appears before the method response, the method is server-side streaming; when `steam` appears both before the method request and the method response, the method is bidirectional. 184 185 The stub code generated by streaming is very different from normal RPC. Take client streaming as an example: 186 ```go 187 type TestStreamService interface { 188 ClientStream(TestStream_ClientStreamServer) error 189 // ... 190 } 191 192 type TestStream_ClientStreamServer interface { 193 SendAndClose(*HelloRsp) error 194 Recv() (*HelloReq, error) 195 server.Stream 196 } 197 198 type TestStreamClientProxy interface { 199 ClientStream(ctx context.Context, opts ...client.Option) (TestStream_ClientStreamClient, error) 200 } 201 202 type TestStream_ClientStreamClient interface { 203 Send(*HelloReq) error 204 CloseAndRecv() (*HelloRsp, error) 205 client.ClientStream 206 } 207 ``` 208 From the stub code above, you can probably guess how the business code is written. The client sends requests multiple times by `TestStream_ClientStreamClient.Send`, and finally closes the stream by `TestStream_ClientStreamClient.CloseAndRecv` and waits for the response. The server receives the client's streaming requests by `TestStream_ClientStreamServer.Recv`, if it returns `io.EOF`, it means that the client has called `CloseAndRecv` and is waiting for the return packet, and it will finally send response by `TestStream_ClientStreamServer.SendAndClose` and confirm to close the stream. Note that the client streaming termination is initialized by the client. `CloseAndRecv` indicates that the client closes first, and then waits for a response. `SendAndClose` indicates that the server sends a response first, and then confirm close. 209 210 Server-side streaming is the opposite of client-side streaming. As soon as the `TestStreamService.ServerStream` function exits, it means that the server has finished sending responses. The client obtains the stream responses by calling `TestStream_ServerStreamClient.Recv` multiple times. When the `io.EOF` error is received, it indicates that the server has completed the stream responses. 211 212 Bidirectional streaming is a combination of the previous two. Their sending and reading can be interleaved, just like two people talking, and more complex interaction logic can be realized. 213 214 The configuration of streaming RPC is no different from normal RPC. 215 216 #### Standard HTTP Service 217 218 tRPC-Go supports registering HTTP services from the Go standard library into the framework. Suppose that you need to listen an HTTP service on port 8080, first, add the following service configuration to `trpc_go.yaml`: 219 ```yaml 220 server: 221 service: 222 - name: std_http 223 ip: 127.0.0.1 224 port: 8080 225 protocol: http 226 ``` 227 Then add following code: 228 ```go 229 import thttp trpc.group/trpc-go/trpc-go/http 230 231 func main() { 232 s := trpc.NewServer() 233 thttp.RegisterNoProtocolServiceMux(s.Service("std_http"), your_http_handler) 234 log.Info(s.Serve()) 235 } 236 ``` 237 238 Note that unlike ordinary RPC, the `protocol` field in yaml needs to be changed to `http`. The first parameter of the `thttp.RegisterNoProtocolServiceMux` method needs to specify the service name in yaml, namely `s.Service("std_http")`. 239 240 #### Translate RPC to HTTP Quickly 241 242 In tRPC-Go, changing `server.service[i].protocol` in `trpc_go.yaml` from `trpc` to `http` can convert the service of ordinary tRPC to HTTP. When calling, the HTTP url corresponds to the [method name](/examples/helloworld/pb/helloworld.trpc.go). 243 244 For example, if you change the RPC in [Quick Start](./quick_start.md) to HTTP, you need to use the following curl command to call it: 245 ```bash 246 $ curl -XPOST -H"Content-Type: application/json" -d'{"msg": "world"}' 127.0.0.1:8000/trpc.helloworld.Greeter/Hello 247 {"msg":"Hello world!"} 248 ``` 249 250 If you need to change the HTTP url, you can add the following extension when declaring the service in protobuf: 251 ```protobuf 252 import "trpc/proto/trpc_options.proto"; 253 254 service Greeter { 255 rpc Hello (HelloRequest) returns (HelloReply) { 256 option (trpc.alias) = "/alias/hello"; 257 } 258 } 259 ``` 260 The curl command is as follows: 261 ```bash 262 $ curl -XPOST -H"Content-Type: application/json" -d'{"msg": "world"}' 127.0.0.1:8000/alias/hello 263 {"msg":"Hello world!"} 264 ``` 265 266 #### RESTful HTTP 267 268 Although it is convenient to quickly convert RPC to HTTP, it is impossible to customize the mapping relationship between HTTP url/parameter/body and RPC Request. RESTful provides a more flexible RPC to HTTP conversion. 269 270 You can refer to [RESTful example](/examples/features/restful) to get start quickly. For more details, please refer to the [documentation](/restful) of RESTful. 271 272 ### Further Reading 273 274 tRPC-Go also supports other rich features, you can check their [documentations](/docs/user_guide) for more details. 275