Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

grpc-gateway Demo #7

Merged
merged 3 commits into from
Jun 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ project/plugins/project/

.DS_Store

/secring.gpg
/secring.gpg
demo/gateway/*json
demo/gateway/*go
18 changes: 17 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
language: scala

sudo: required

scala:
- 2.11.11
- 2.12.2

jdk:
- oraclejdk8

env:
global:
- GOPATH="${HOME}/go"
- PATH="${GOPATH}/bin:${PATH}"

before_cache:
- du -h -d 1 $HOME/.ivy2/
- du -h -d 2 $HOME/.sbt/
Expand All @@ -28,9 +35,18 @@ before_install:
- if [ "$TRAVIS_BRANCH" = "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then
openssl aes-256-cbc -K $encrypted_80bb47bfd841_key -iv $encrypted_80bb47bfd841_iv -in secring.gpg.enc -out secring.gpg -d;
fi
- sh ./scripts/protobuf.sh
- sh ./scripts/gimme.sh

install:
- go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
- go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
- go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
- go get -u -v google.golang.org/grpc
- go get -u github.com/golang/protobuf/protoc-gen-go

script:
- sbt ++$TRAVIS_SCALA_VERSION orgScriptCI
- sbt -Dgo.path=$GOPATH ++$TRAVIS_SCALA_VERSION orgScriptCI

after_success:
- bash <(curl -s https://codecov.io/bash) -t 5b75b318-ab71-4fbc-9203-bfa7765cdbdc
Expand Down
98 changes: 97 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

Simple RPC with Freestyle

## Demo
## Greeting Demo

Run server:

Expand All @@ -23,6 +23,102 @@ Run client:
sbt runClient
```

## User Demo

Based on https://github.com/grpc-ecosystem/grpc-gateway.

[grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) is a plugin of protoc. It reads gRPC service definition, and generates a reverse-proxy server which translates a RESTful JSON API into gRPC. This server is generated according to custom options in your gRPC definition.
This server is generated according to [custom options](https://cloud.google.com/service-management/reference/rpc/google.api#http) in your gRPC definition.

### Prerequisites

It's mandatory to follow these [instructions](https://github.com/grpc-ecosystem/grpc-gateway#installation) before proceeding. You might want use `brew install protobuf` if you're using OSX.

And then:

```bash
$ brew install go
$ go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
$ go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
$ go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
$ go get -u -v google.golang.org/grpc
$ go get -u github.com/golang/protobuf/protoc-gen-go
```

Finally, make sure that your `$GOPATH/bin` is in your `$PATH`.

### Troubleshooting

#### `failed to run aclocal: No such file or directory`

The development release of a program source code often comes with `autogen.sh` which is used to prepare a build process, including verifying program functionality and generating configure script. This `autogen.sh` script then relies on `autoreconf` to invoke `autoconf`, `automake`, `aclocal` and other related tools.

The missing `aclocal` is part of `automake` package. Thus, to fix this error, install `automake` package.

* `OSX`:

https://gist.github.com/justinbellamy/2672db1c78f024f2d4fe

* `Debian`, `Ubuntu` or `Linux Mint`:

```bash
$ sudo apt-get install automake
```

* `CentOS`, `Fedora` or `RHEL`:

```bash
$ sudo yum install automake
```

## Run Demo

### Running the Server

```
sbt -Dgo.path=$GOPATH ";project demo;runMain freestyle.rpc.demo.user.UserServerApp"
```

### Running the Client

Now, you could invoke the service:

* Using the client, as usual:

```
sbt -Dgo.path=$GOPATH ";project demo;runMain freestyle.rpc.demo.user.UserClientApp"
```

### Generating and Running the Gateway

You could generate a reverse proxy and writing an endpoint as it's described [here](https://github.com/grpc-ecosystem/grpc-gateway#usage).



To run the gateway:

```bash
go run demo/gateway/server/entry.go
```

Then, you could use `curl` or similar to fetch the user over `HTTP`:

```bash
curl -X POST \
-H "Content-Type: application/json" \
-H "Cache-Control: no-cache" \
-H "Postman-Token: 1e813409-6aa6-8cd1-70be-51305f31667f" \
-d '{
"password" : "password"
}' "http://127.0.0.1:8080/v1/frees"
```

HTTP Response:

```bash
{"name":"Freestyle","email":"hello@frees.io"}%
```

[comment]: # (Start Copyright)
# Copyright

Expand Down
30 changes: 25 additions & 5 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ lazy val root = project
.settings(name := "freestyle-rpc")
.settings(moduleName := "root")
.settings(noPublishSettings: _*)
.aggregate(rpc, demo)
.aggregate(rpc, googleApi, demo)

lazy val rpc = project
.in(file("rpc"))
Expand All @@ -20,19 +20,39 @@ lazy val rpc = project
): _*
)

lazy val GOPATH = Option(sys.props("go.path")).getOrElse("/your/go/path")

lazy val googleApi = project
.in(file("third_party"))
.settings(
PB.protoSources.in(Compile) ++= Seq(
file(s"$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/")
),
PB.targets.in(Compile) := Seq(scalapb.gen() -> sourceManaged.in(Compile).value),
libraryDependencies += "com.trueaccord.scalapb" %% "scalapb-runtime" % cv.scalapbVersion % "protobuf"
)

lazy val demo = project
.in(file("demo"))
.aggregate(rpc)
.dependsOn(rpc)
.aggregate(rpc, googleApi)
.dependsOn(rpc, googleApi)
.settings(moduleName := "freestyle-rpc-demo")
.settings(noPublishSettings: _*)
.settings(commandAliases: _*)
.settings(
Seq(
PB.protoSources.in(Compile) := Seq(sourceDirectory.in(Compile).value / "proto"),
PB.protocOptions.in(Compile) ++= Seq(
"-I/usr/local/include -I.",
s"-I$GOPATH/src",
s"-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis",
"--go_out=plugins=grpc:./demo/gateway",
"--grpc-gateway_out=logtostderr=true:./demo/gateway",
"--swagger_out=logtostderr=true:./demo/gateway"
),
PB.protoSources.in(Compile) ++= Seq(sourceDirectory.in(Compile).value / "proto"),
PB.targets.in(Compile) := Seq(scalapb.gen() -> sourceManaged.in(Compile).value),
libraryDependencies ++= Seq(
"io.grpc" % "grpc-netty" % cv.grpcJavaVersion,
"io.grpc" % "grpc-all" % cv.grpcJavaVersion,
"com.trueaccord.scalapb" %% "scalapb-runtime" % cv.scalapbVersion % "protobuf",
"com.trueaccord.scalapb" %% "scalapb-runtime-grpc" % cv.scalapbVersion
)
Expand Down
41 changes: 41 additions & 0 deletions demo/gateway/server/entry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package main

import (
"flag"
"net/http"

"github.com/golang/glog"
"golang.org/x/net/context"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"google.golang.org/grpc"

gw ".."
)

var (
userEndpoint = flag.String("user_endpoint", "localhost:50051", "/")
)

func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()

mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := gw.RegisterUserServiceHandlerFromEndpoint(ctx, mux, *userEndpoint, opts)
if err != nil {
return err
}

return http.ListenAndServe(":8080", mux)
}

func main() {
flag.Parse()
defer glog.Flush()

if err := run(); err != nil {
glog.Fatal(err)
}
}
24 changes: 24 additions & 0 deletions demo/src/main/proto/user.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
syntax = "proto3";

package freestyle.rpc.demo;

import "google/api/annotations.proto";

service UserService {
rpc Login (UserPassword) returns (User) {
option (google.api.http) = {
post: "/v1/{login=*}"
body: "*"
};
}
}

message UserPassword {
string login = 1;
string password = 2;
}

message User {
string name = 1;
string email = 2;
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ class GreetingService extends GreeterGrpc.Greeter {
responseObserver.onCompleted()
}

override def onNext(value: MessageRequest): Unit =
override def onNext(value: MessageRequest): Unit = {
responseObserver.onNext(MessageReply(s"$loggerInfo - I did receive $value"))
println(s"[$loggerInfo] This is your message ${counter.incrementAndGet()}, ${value.name}")
}
}
}
4 changes: 2 additions & 2 deletions demo/src/main/scala/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* limitations under the License.
*/

package freestyle.rpc.demo
package freestyle.rpc

package object greeting {
package object demo {

val host = "localhost"
val port = 50051
Expand Down
35 changes: 35 additions & 0 deletions demo/src/main/scala/user/UserClient.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2017 47 Degrees, LLC. <http://www.47deg.com>
*
* 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.
*/

package freestyle.rpc.demo
package user

import freestyle.rpc.demo.user.UserServiceGrpc.UserServiceStub
import io.grpc.ManagedChannelBuilder

import scala.concurrent.{Await, Future}
import scala.concurrent.duration._

class UserClient(host: String, port: Int) {

private[this] val channel =
ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build

private[this] val client: UserServiceStub = UserServiceGrpc.stub(channel)

def login(request: UserPassword): Future[User] =
client.login(request)
}
33 changes: 33 additions & 0 deletions demo/src/main/scala/user/UserClientApp.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2017 47 Degrees, LLC. <http://www.47deg.com>
*
* 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.
*/

package freestyle.rpc.demo
package user

import scala.concurrent.Await
import scala.concurrent.duration.Duration

object UserClientApp {

def main(args: Array[String]): Unit = {
val request = UserPassword("frees", "password")
val client = new UserClient(host, port)

val response = client.login(request)

println(s"Login Result -> ${Await.result(response, Duration.Inf)}")
}
}
Loading