Skip to content

Commit

Permalink
[GSoD] Added tutorials directory on gRPC-Gateway (grpc-ecosystem#1829)
Browse files Browse the repository at this point in the history
* added tutorials directory on grpc-gateway

* refactored badges and links

* added requested changes

* updated tutorials directory on grpc-gateway

* updated tutorials directory on grpc-gateway

* updated tutorials directory on grpc-gateway

* updated tutorials

* updated tutorials

* updated tutorials

* updated tutorials

* updated headings and added next button for tutorials

* updated next buttons

* updated tutorials

* updated tutorials

* updated tutorials

* updated tutorials

* updated tutorials

* updated tutorials

* added helloworld link
  • Loading branch information
iamrajiv authored Dec 1, 2020
1 parent 0096364 commit 806c563
Show file tree
Hide file tree
Showing 11 changed files with 460 additions and 4 deletions.
2 changes: 1 addition & 1 deletion docs/docs/faq.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
layout: default
title: FAQ
nav_order: 7
nav_order: 8
---

# FAQ
Expand Down
200 changes: 200 additions & 0 deletions docs/docs/tutorials/adding_annotations.md
Original file line number Diff line number Diff line change
@@ -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 }
56 changes: 56 additions & 0 deletions docs/docs/tutorials/creating_main.go.md
Original file line number Diff line number Diff line change
@@ -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 }
9 changes: 9 additions & 0 deletions docs/docs/tutorials/generating_stubs/index.md
Original file line number Diff line number Diff line change
@@ -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.
49 changes: 49 additions & 0 deletions docs/docs/tutorials/generating_stubs/using_buf.md
Original file line number Diff line number Diff line change
@@ -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 }
24 changes: 24 additions & 0 deletions docs/docs/tutorials/generating_stubs/using_protoc.md
Original file line number Diff line number Diff line change
@@ -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 }
6 changes: 6 additions & 0 deletions docs/docs/tutorials/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
layout: default
title: Tutorials
nav_order: 7
has_children: true
---
Loading

0 comments on commit 806c563

Please sign in to comment.