diff --git a/docs/docs/faq.md b/docs/docs/faq.md index 5457f350e04..875f28a1985 100644 --- a/docs/docs/faq.md +++ b/docs/docs/faq.md @@ -1,7 +1,7 @@ --- layout: default title: FAQ -nav_order: 7 +nav_order: 8 --- # FAQ diff --git a/docs/docs/tutorials/adding_annotations.md b/docs/docs/tutorials/adding_annotations.md new file mode 100644 index 00000000000..dbf1668edb2 --- /dev/null +++ b/docs/docs/tutorials/adding_annotations.md @@ -0,0 +1,200 @@ +--- +layout: default +title: Adding the grpc-gateway annotations to an existing protobuf file +parent: Tutorials +nav_order: 5 +--- + +# Adding the grpc-gateway annotations to an existing protobuf file + +Now that we've got a working Go gRPC server, we need to add the grpc-gateway annotations. + +The annotations define how gRPC services map to the JSON request and response. When using protocol buffers, each RPC must define the HTTP method and path using the `google.api.http` annotation. + +So we will need to add the `google/api/http.proto` import to the proto file. We also need to add the HTTP->gRPC mapping we want. In this case, we're mapping `POST /v1/example/echo` to our `SayHello` rpc. + +```proto +syntax = "proto3"; + +package helloworld; + +import "google/api/annotations.proto"; + +// Here is the overall greeting service definition where we define all our endpoints +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) { + option (google.api.http) = { + post: "/v1/example/echo" + body: "*" + }; + } +} + +// The request message containing the user's name +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} +``` + +See [a_bit_of_everything.proto](https://github.com/grpc-ecosystem/grpc-gateway/blob/master/examples/internal/proto/examplepb/a_bit_of_everything.proto) for examples of more annotations you can add to customize gateway behavior. + +## Generating the grpc-gateway stubs + +Now that we've got the grpc-gateway annotations added to the proto file, we need to use the grpc-gateway generator to generate the stubs. + +Before we can do that, we need to copy some dependencies into our protofile structure. Copy the `third_party/googleapis` folder from the grpc-gateway repository to your local protofile structure. It should look like this afterwards: + +``` +proto +├── google +│ └── api +│ ├── annotations.proto +│ └── http.proto +└── helloworld + └── hello_world.proto +``` + +### Using buf + +We'll need to add the grpc-gateway generator to the generation configuration: + +```yml +version: v1beta1 +plugins: + - name: go + out: proto + opt: paths=source_relative + - name: go-grpc + out: proto + opt: paths=source_relative,require_unimplemented_servers=false + - name: grpc-gateway + out: proto + opt: paths=source_relative +``` + +And that's it! Now if you run: + +```sh +$ buf generate +``` + +It should produce a `*.gw.pb.go` file. + +### Using protoc + +Now we need to add the grpc-gateway generator to the protoc invocation: + +```sh +$ protoc -I ./proto \ + --go_out ./proto --go_opt paths=source_relative \ + --go-grpc_out ./proto --go-grpc_opt paths=source_relative \ + --grpc-gateway_out ./proto --grpc-gateway_opt paths=source_relative \ + ./proto/helloworld/hello_world.proto +``` + +This should generate a `*.gw.pb.go` file. + +We also need to add and serve the gRPC-gateway mux in our `main.go` file. + +```go +package main + +import ( + "context" + "log" + "net" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "google.golang.org/grpc" + + helloworldpb "github.com/myuser/myrepo/proto/helloworld" +) + +type server struct{} + +func NewServer() *server { + return &server{} +} + +func (s *server) SayHello(ctx context.Context, in *helloworldpb.HelloRequest) (*helloworldpb.HelloReply, error) { + return &helloworldpb.HelloReply{Message: in.Name + " World"}, nil +} + +func main() { + // Create a listener on TCP port + lis, err := net.Listen("tcp", ":8080") + if err != nil { + log.Fatalln("Failed to listen:", err) + } + + // Create a gRPC server object + s := grpc.NewServer() + // Attach the Greeter service to the server + helloworldpb.RegisterGreeterServer(s, &server{}) + // Serve gRPC Server + log.Println("Serving gRPC on 0.0.0.0:8080") + go func() { + log.Fatalln(s.Serve(lis)) + }() + + // Create a client connection to the gRPC Server we just started + // This is where the gRPC-Gateway proxies the requests + conn, err := grpc.DialContext( + context.Background(), + "0.0.0.0:8080", + grpc.WithBlock(), + grpc.WithInsecure(), + ) + if err != nil { + log.Fatalln("Failed to dial server:", err) + } + + gwmux := runtime.NewServeMux() + // Register Greeter + err = helloworldpb.RegisterGreeterHandler(context.Background(), gwmux, conn) + if err != nil { + log.Fatalln("Failed to register gateway:", err) + } + + gwServer := &http.Server{ + Addr: ":8090", + Handler: gwmux, + } + + log.Println("Serving gRPC-Gateway on http://0.0.0.0:8090") + log.Fatalln(gwServer.ListenAndServe()) +} +``` + +For more examples, please refer to [our boilerplate repository](https://github.com/johanbrandhorst/grpc-gateway-boilerplate). + +## Testing the gRPC-Gateway + +Now we can start the server: + +```sh +$ go run main.go +``` + +Then we use cURL to send HTTP requests: + +```sh +$ curl -X POST -k http://localhost:8090/v1/example/echo -d '{"name": " Hello"}' +``` + +``` +{"message":"Hello World"} +``` + +Hopefully, that gives a bit of understanding of how to use the gRPC-Gateway. + +Full source code of hello world can be found here [helloworld-grpc-gateway](https://github.com/iamrajiv/helloworld-grpc-gateway) + +[Next](learn_more.md){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 } diff --git a/docs/docs/tutorials/creating_main.go.md b/docs/docs/tutorials/creating_main.go.md new file mode 100644 index 00000000000..669dfac31e5 --- /dev/null +++ b/docs/docs/tutorials/creating_main.go.md @@ -0,0 +1,56 @@ +--- +layout: default +title: Creating main.go +parent: Tutorials +nav_order: 4 +--- + +# Creating main.go + +Before creating `main.go` file we are assuming that the user has created a `go.mod` with the name `github.com/myuser/myrepo`, if not please refer to [Creating go.mod file](introduction.md#creating-gomod-file). The import here is using the path to the generated files in `proto/helloworld` relative to the root of the repository. + +```go +package main + +import ( + "context" + "log" + "net" + + "google.golang.org/grpc" + + helloworldpb "github.com/myuser/myrepo/proto/helloworld" +) + +type server struct{} + +func NewServer() *server { + return &server{} +} + +func (s *server) SayHello(ctx context.Context, in *helloworldpb.HelloRequest) (*helloworldpb.HelloReply, error) { + return &helloworldpb.HelloReply{Message: in.Name + " World"}, nil +} + +func main() { + // Create a listener on TCP port + lis, err := net.Listen("tcp", ":8080") + if err != nil { + log.Fatalln("Failed to listen:", err) + } + + // Create a gRPC server object + s := grpc.NewServer() + // Attach the Greeter service to the server + helloworldpb.RegisterGreeterServer(s, &server{}) + // Serve gRPC Server + log.Println("Serving gRPC on 0.0.0.0:8080") + log.Fatal(s.Serve(lis)) +} +``` + +## Read More + +For more refer to gRPC docs [https://grpc.io/docs/languages/go/](https://grpc.io/docs/languages/go/). + +[Next](adding_annotations.md){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 } diff --git a/docs/docs/tutorials/generating_stubs/index.md b/docs/docs/tutorials/generating_stubs/index.md new file mode 100644 index 00000000000..172467df30f --- /dev/null +++ b/docs/docs/tutorials/generating_stubs/index.md @@ -0,0 +1,9 @@ +--- +layout: default +title: Generating stubs +parent: Tutorials +nav_order: 3 +has_children: true +--- + +For generating the stubs, we have two alternatives: `protoc` and `buf`. `protoc` is the more classic generation experience that is used widely in the industry, but it has a pretty steep learning curve. `buf` is a newer tool that is built with user experience and speed in mind. It also offers linting and breaking change detection, something `protoc` doesn't offer. We offer instructions for both here. diff --git a/docs/docs/tutorials/generating_stubs/using_buf.md b/docs/docs/tutorials/generating_stubs/using_buf.md new file mode 100644 index 00000000000..392c5470ca2 --- /dev/null +++ b/docs/docs/tutorials/generating_stubs/using_buf.md @@ -0,0 +1,49 @@ +--- +layout: default +title: Generating stubs using buf +parent: Generating stubs +grand_parent: Tutorials +nav_order: 1 +--- + +# Generating stubs using buf + +[Buf](https://github.com/bufbuild/buf) is a tool that provides various protobuf utilities such as linting, breaking change detection and generation. Please find installation instructions on [https://docs.buf.build/installation/](https://docs.buf.build/installation/). + +It is configured through a `buf.yaml` file that should be checked in to the root of your repository. Buf will automatically read this file if present. Configuration can also be provided via the command-line flag `--config`, which accepts a path to a `.json` or `.yaml` file, or direct JSON or YAML data. + +All Buf operations that use your local `.proto` files as input rely on a valid build configuration. This configuration tells Buf where to search for `.proto` files, and how to handle imports. As opposed to `protoc`, where all `.proto` files are manually specified on the command-line, buf operates by recursively discovering all `.proto` files under configuration and building them. + +The following is an example of a valid configuration, assuming you have your `.proto` files rooted in the `proto` folder relative to the root of your repository. + +```yml +version: v1beta1 +build: + roots: + - proto +``` + +To generate type and gRPC stubs for Go, create the file `buf.gen.yaml` at the root of the repository: + +```yml +version: v1beta1 +plugins: + - name: go + out: proto + opt: paths=source_relative + - name: go-grpc + out: proto + opt: paths=source_relative +``` + +We use the `go` and `go-grpc` plugins to generate Go types and gRPC service definitions. We're outputting the generated files relative to the `proto` folder, and we're using the `paths=source_relative` option, which means that the generated files will appear in the same directory as the source `.proto` file. + +Then run + +```sh +$ buf generate +``` + +This will have generated a `*.pb.go` and a `*_grpc.pb.go` file for each protobuf package in our `proto` file hierarchy. + +[Next](../creating_main.go.md){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 } diff --git a/docs/docs/tutorials/generating_stubs/using_protoc.md b/docs/docs/tutorials/generating_stubs/using_protoc.md new file mode 100644 index 00000000000..240fe0e4689 --- /dev/null +++ b/docs/docs/tutorials/generating_stubs/using_protoc.md @@ -0,0 +1,24 @@ +--- +layout: default +title: Generating stubs using protoc +parent: Generating stubs +grand_parent: Tutorials +nav_order: 2 +--- + +# Generating stubs using protoc + +Here's an example of what a `protoc` command might look like to generate Go stubs, assuming that you're at the root of your repository and you have your proto files in a directory called `proto`: + +```sh +$ protoc -I ./proto \ + --go_out ./proto --go_opt paths=source_relative \ + --go-grpc_out ./proto --go-grpc_opt paths=source_relative \ + ./proto/helloworld/hello_world.proto +``` + +We use the `go` and `go-grpc` plugins to generate Go types and gRPC service definitions. We're outputting the generated files relative to the `proto` folder, and we're using the `paths=source_relative` option, which means that the generated files will appear in the same directory as the source `.proto` file. + +This will have generated a `*.pb.go` and a `*_grpc.pb.go` file for `proto/helloworld/hello_world.proto`. + +[Next](../creating_main.go.md){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 } diff --git a/docs/docs/tutorials/index.md b/docs/docs/tutorials/index.md new file mode 100644 index 00000000000..af5856ec9e3 --- /dev/null +++ b/docs/docs/tutorials/index.md @@ -0,0 +1,6 @@ +--- +layout: default +title: Tutorials +nav_order: 7 +has_children: true +--- diff --git a/docs/docs/tutorials/introduction.md b/docs/docs/tutorials/introduction.md new file mode 100644 index 00000000000..4d838329187 --- /dev/null +++ b/docs/docs/tutorials/introduction.md @@ -0,0 +1,52 @@ +--- +layout: default +title: Introduction to the gRPC-Gateway +parent: Tutorials +nav_order: 1 +--- + +# Introduction to the gRPC-Gateway + +We all know that gRPC is not a tool for everything. There are cases where we still want to provide a traditional HTTP/JSON API. The reasons can range from maintaining backward-compatibility to supporting programming languages or clients not well supported by gRPC. But writing another service just to expose an HTTP/JSON API is quite a time consuming and tedious task. + +So is there any way to code just once, but provide APIs in both gRPC and HTTP/JSON at the same time? + +The answer is Yes. + +The grpc-gateway is a plugin of the Google protocol buffers compiler [protoc](https://github.com/protocolbuffers/protobuf). It reads protobuf service definitions and generates a reverse-proxy server which translates a RESTful HTTP API into gRPC. This server is generated according to the [`google.api.http`](https://github.com/googleapis/googleapis/blob/master/google/api/http.proto#L46) annotations in your service definitions. + +This helps you provide your APIs in both gRPC and HTTP/JSON format at the same time. + +![architecture introduction diagram](https://docs.google.com/drawings/d/12hp4CPqrNPFhattL_cIoJptFvlAqm5wLQ0ggqI5mkCg/pub?w=749&h=370) + +## Prerequisites + +Before we start coding, we have to install some tools. + +We will be using a Go gRPC server in the examples, so please install Go first from [https://golang.org/dl/](https://golang.org/dl/). + +After installing Go, use `go get` to download the following packages: + +```sh +$ go get github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway +$ go get google.golang.org/protobuf/cmd/protoc-gen-go +$ go get google.golang.org/grpc/cmd/protoc-gen-go-grpc +``` + +This installs the protoc generator plugins we need to generate the stubs. Make sure to add `$GOPATH/bin` to your `$PATH` so that executables installed via `go get` are available on your `$PATH`. +We will be working in a new module for this tutorial, so go ahead and create that in a folder of your choosing now: + +### Creating go.mod file + +Start your module using the [go mod init command](https://golang.org/cmd/go/#hdr-Initialize_new_module_in_current_directory) to create a go.mod file. + +Run the `go mod init` command, giving it the path of the module your code will be in. Here, use github.com/myuser/myrepo for the module path -- in production code, this would be the URL from which your module can be downloaded. + +```sh +$ go mod init github.com/myuser/myrepo +go: creating new go.mod: module github.com/myuser/myrepo +``` + +The `go mod init` command creates a go.mod file that identifies your code as a module that might be used from other code. The file you just created includes only the name of your module and the Go version your code supports. But as you add dependencies -- meaning packages from other modules -- the go.mod file will list the specific module versions to use. This keeps builds reproducible and gives you direct control over which module versions to use. + +[Next](simple_hello_world.md){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 } diff --git a/docs/docs/tutorials/learn_more.md b/docs/docs/tutorials/learn_more.md new file mode 100644 index 00000000000..c912c7c1ccc --- /dev/null +++ b/docs/docs/tutorials/learn_more.md @@ -0,0 +1,20 @@ +--- +layout: default +title: Learn More +parent: Tutorials +nav_order: 6 +--- + +# Learn More + +## How it works + +When the HTTP request arrives at the gRPC-gateway, it parses the JSON data into a protobuf message. It then makes a normal Go gRPC client request using the parsed protobuf message. The Go gRPC client encodes the protobuf structure into the protobuf binary format and sends it to the gRPC server. The gRPC Server handles the request and returns the response in the protobuf binary format. The Go gRPC client parses it into a protobuf message and returns it to the gRPC-gateway, which encodes the protobuf message to JSON and returns it to the original client. + +## google.api.http + +Read more about `google.api.http` on [https://github.com/googleapis/googleapis/blob/master/google/api/http.proto](https://github.com/googleapis/googleapis/blob/master/google/api/http.proto) + +## HTTP and gRPC Transcoding + +Read more about HTTP and gRPC Transcoding on [https://google.aip.dev/127](https://google.aip.dev/127) diff --git a/docs/docs/tutorials/simple_hello_world.md b/docs/docs/tutorials/simple_hello_world.md new file mode 100644 index 00000000000..7347a534687 --- /dev/null +++ b/docs/docs/tutorials/simple_hello_world.md @@ -0,0 +1,40 @@ +--- +layout: default +title: Creating a simple hello world with gRPC +parent: Tutorials +nav_order: 2 +--- + +# Creating a simple hello world with gRPC + +To understand the gRPC-Gateway we are going to first make a hello world gRPC service. + +## Defining your gRPC service using protocol buffers + +Before we create a gRPC service, we should create a proto file to define what we need, here we create a file named `hello_world.proto` in the directory `proto/helloworld/hello_world.proto`. + +The gRPC service is defined using [Google Protocol Buffers](https://developers.google.com/protocol-buffers). To learn more about how to define a service in a `.proto` file see their [Basics tutorial](https://grpc.io/docs/languages/go/basics/). For now, all you need to know is that both the server and the client stub have a `SayHello()` RPC method that takes a `HelloRequest` parameter from the client and returns a `HelloReply` from the server, and that the method is defined like this: + +```proto +syntax = "proto3"; + +package helloworld; + +// The greeting service definition +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} +``` + +[Next](generating_stubs/index.md){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 } diff --git a/docs/index.md b/docs/index.md index 397dd66dedb..0f702c8e09a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -19,13 +19,13 @@ This server is generated according to [custom options](https://cloud.google.com/ --- -## About +## Getting started [![circleci](https://img.shields.io/circleci/build/github/grpc-ecosystem/grpc-gateway?color=379c9c&logo=circleci&logoColor=ffffff&style=flat-square)](https://circleci.com/gh/grpc-ecosystem/grpc-gateway) [![codecov](https://img.shields.io/codecov/c/github/grpc-ecosystem/grpc-gateway?color=379c9c&logo=codecov&logoColor=ffffff&style=flat-square)](https://codecov.io/gh/grpc-ecosystem/grpc-gateway) -[![forks](https://img.shields.io/github/forks/grpc-ecosystem/grpc-gateway?color=379c9c&style=flat-square)](https://github.com/grpc-ecosystem/grpc-gateway/network/members) -[![issues](https://img.shields.io/github/issues/grpc-ecosystem/grpc-gateway?color=379c9c&style=flat-square)](https://github.com/grpc-ecosystem/grpc-gateway/issues) +[![slack](https://img.shields.io/badge/slack-grpc--gateway-379c9c?logo=slack&logoColor=ffffff&style=flat-square)](https://app.slack.com/client/T029RQSE6/CBATURP1D) [![license](https://img.shields.io/github/license/grpc-ecosystem/grpc-gateway?color=379c9c&style=flat-square)](https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt) +[![release](https://img.shields.io/github/v/release/grpc-ecosystem/grpc-gateway?color=379c9c&logoColor=ffffff&style=flat-square)](https://github.com/grpc-ecosystem/grpc-gateway/releases) [![stars](https://img.shields.io/github/stars/grpc-ecosystem/grpc-gateway?color=379c9c&style=flat-square)](https://github.com/grpc-ecosystem/grpc-gateway/stargazers) grpc-gateway is a plugin of [protoc](https://github.com/protocolbuffers/protobuf).