Skip to content

Commit

Permalink
Fixed for Support grpc-gateway generate_unbound_methods option #226 (#…
Browse files Browse the repository at this point in the history
…227)

* Fixed for Support grpc-gateway generate_unbound_methods option #226

* test for Support grpc-gateway generate_unbound_methods option #226

* test for Support grpc-gateway generate_unbound_methods option #226

Co-authored-by: Ido David <[email protected]>
  • Loading branch information
juandemanjon and ido-namely authored Jan 10, 2022
1 parent e382d24 commit 1c2146e
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 9 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ docker build -t my-grpc-gateway gen/grpc-gateway/

_NOTE_: If your service does not contain any `(google.api.http)` annotations, this build will
fail with an error `...HandlerFromEndpoint is undefined`. You need to have at least one rpc
method annotated to build a gRPC Gateway.
method annotated to build a gRPC Gateway, or use `--generate-unbound-methods` option to expose
all the methods in your proto file

Run this image with

Expand Down Expand Up @@ -279,6 +280,12 @@ CONTAINER=namely/protoc-all:VVV make test
(`VVV` is your version from the tag in the console output when running `make build`.) Running this will
demonstrate that your new image can successfully build containers for each language.

#### gRPC Gateway test
```sh
cd gwy
./test.sh namely/gen-grpc-gateway:VVV
```

### Release

Handled automatically via CI (githubaction).
Expand Down
15 changes: 12 additions & 3 deletions all/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ printUsage() {
echo " --with-swagger-json-names Use with --with-gateway flag. Generated swagger file will use JSON names instead of protobuf names.
(deprecated. Please use --with-openapi-json-names)"
echo " --with-openapi-json-names Use with --with-gateway flag. Generated OpenAPI file will use JSON names instead of protobuf names."
echo " --generate-unbound-methods Use with --with-gateway flag. Produce the HTTP mapping even for methods without any HttpRule annotation."
echo " --js-out This option overrides the 'js_out=' argument in the grpc-node and grpc-web code generation. Defaults to 'import_style=commonjs'."
echo " --grpc-out This option allows overriding the left-half of the 'grpc_out=' argument (before the colon) with grpc-node and grpc-web code generation. Options are: generate_package_definition, grpc_js or grpc(depricated from April 2021). Defaults to grpc_js."
echo " --grpc-web-out This option overrides the 'grpc-web_out=' argument in the grpc-web code generation. Defaults to 'import_style=typescript'."
Expand Down Expand Up @@ -64,6 +65,7 @@ DESCR_FILENAME="descriptor_set.pb"
CSHARP_OPT=""
SCALA_OPT=""
OPENAPI_JSON=false
GENERATE_UNBOUND_METHODS=false
JS_OUT="import_style=commonjs"
WEB_OUT="import_style=typescript"
GRPC_OUT="grpc_js"
Expand Down Expand Up @@ -207,6 +209,10 @@ while test $# -gt 0; do
OPENAPI_JSON=true
shift
;;
--generate-unbound-methods)
GENERATE_UNBOUND_METHODS=true
shift
;;
--js-out)
shift
JS_OUT=$1
Expand Down Expand Up @@ -458,13 +464,16 @@ if [ $GEN_GATEWAY = true ]; then
mkdir -p ${GATEWAY_DIR}

protoc $PROTO_INCLUDE \
--grpc-gateway_out=logtostderr=true:$GATEWAY_DIR ${PROTO_FILES[@]}
--grpc-gateway_out=logtostderr=true:$GATEWAY_DIR ${PROTO_FILES[@]} \
--grpc-gateway_opt generate_unbound_methods=$GENERATE_UNBOUND_METHODS

if [[ $OPENAPI_JSON == true ]]; then
protoc $PROTO_INCLUDE \
--openapiv2_out=logtostderr=true,json_names_for_fields=true:$GATEWAY_DIR ${PROTO_FILES[@]}
--openapiv2_out=logtostderr=true,json_names_for_fields=true:$GATEWAY_DIR ${PROTO_FILES[@]} \
--openapiv2_opt generate_unbound_methods=$GENERATE_UNBOUND_METHODS
else
protoc $PROTO_INCLUDE \
--openapiv2_out=logtostderr=true,json_names_for_fields=false:$GATEWAY_DIR ${PROTO_FILES[@]}
--openapiv2_out=logtostderr=true,json_names_for_fields=false:$GATEWAY_DIR ${PROTO_FILES[@]} \
--openapiv2_opt generate_unbound_methods=$GENERATE_UNBOUND_METHODS
fi
fi
18 changes: 18 additions & 0 deletions all/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ fi

JSON_PARAM_NAME="additionalParam"

UNBOUND_METHOD="UnboundUnary"

# Checks that directories were appropriately created, and deletes the generated directory.
testGeneration() {
lang=$1
Expand Down Expand Up @@ -126,6 +128,19 @@ testGeneration() {
echo "$expected_file_name2 file was not generated with json names"
exit 1
fi
elif [[ "$extra_args" == *"--generate-unbound-methods"* ]]; then
# Test that we have mapped the unbound method
if ! grep -q $UNBOUND_METHOD "$expected_output_dir$expected_file_name1" ; then
echo "$expected_file_name1 does not contain the expected method $UNBOUND_METHOD"
exit 1
fi
else
# No extra arguments
# Test that we haven't mapped the unbound method
if grep -q $UNBOUND_METHOD "$expected_output_dir$expected_file_name1" ; then
echo "$expected_file_name1 should not contain the unexpected method $UNBOUND_METHOD"
exit 1
fi
fi
fi

Expand Down Expand Up @@ -241,6 +256,9 @@ testGeneration go "gen/pb-go" 0 --with-gateway --with-openapi-json-names
# Test grpc-gateway generation + json (deprecated) (only valid for Go)
testGeneration go "gen/pb-go" 0 --with-gateway --with-swagger-json-names

# Test grpc-gateway generation with unbound methods (only valid for Go)
testGeneration go "gen/pb-go" 0 --with-gateway --generate-unbound-methods

# Test go source relative generation
testGeneration go "gen/pb-go" 0 --go-source-relative

Expand Down
4 changes: 4 additions & 0 deletions all/test/test.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ service Message {
body: "*"
};
}
rpc UnboundUnary (UnboundUnaryRequest) returns (UnboundUnaryResponse) {}
}

message ListMessageRequest {
Expand All @@ -33,3 +34,6 @@ message UpdateMessageRequest {
}

message UpdateMessageResponse {}

message UnboundUnaryRequest {}
message UnboundUnaryResponse {}
14 changes: 13 additions & 1 deletion gwy/generate_gateway.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ printUsage() {
echo "-a, --additional_interfaces The set of additional interfaces to bind to this gateway."
echo "-o, --out DIRECTORY Optional. The output directory for the gateway. By default, gen/grpc-gateway."
echo "--go-package-map Optional. Map proto imports to go import paths"
echo "--generate-unbound-methods Optional. Produce the HTTP mapping even for methods without any HttpRule annotation."
}

# Path to the proto file
Expand All @@ -26,6 +27,8 @@ OUT_DIR=""
GO_PACKAGE_MAP=""
# Extra includes.
INCLUDES=""
# Generate unbound methods
GENERATE_UNBOUND_METHODS=false

while test $# -gt 0; do
case "$1" in
Expand Down Expand Up @@ -95,6 +98,10 @@ while test $# -gt 0; do
fi
shift
;;
--generate-unbound-methods)
GENERATE_UNBOUND_METHODS=true
shift
;;
*)
echo "Unrecognized option or argument: $1 in $@"
echo ""
Expand Down Expand Up @@ -123,7 +130,12 @@ fi
# Generate the gateway files
PROTO_DIR=$(dirname $FILE)
GEN_PATH=${OUT_DIR}/gen/
entrypoint.sh -d ${PROTO_DIR} -l go --with-gateway -o ${GEN_PATH} --go-package-map ${GO_PACKAGE_MAP} ${INCLUDES}

if [ $GENERATE_UNBOUND_METHODS = true ]; then
entrypoint.sh -d ${PROTO_DIR} -l go --with-gateway --generate-unbound-methods -o ${GEN_PATH} --go-package-map ${GO_PACKAGE_MAP} ${INCLUDES}
else
entrypoint.sh -d ${PROTO_DIR} -l go --with-gateway -o ${GEN_PATH} --go-package-map ${GO_PACKAGE_MAP} ${INCLUDES}
fi

GATEWAY_IMPORT_DIR=`find ${GEN_PATH} -type f -name "*.gw.go" -print | head -n 1 | xargs -n1 dirname`
GATEWAY_IMPORT_DIR=${GATEWAY_IMPORT_DIR#"$OUT_DIR/"}
Expand Down
72 changes: 69 additions & 3 deletions gwy/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,65 @@ fi
CONTAINER=$1
HEADERS_FILE="./.headers"
SOME_RESP_HEADER="SOME-RESPONSE-HEADER"

# Test building the gateway.
docker run --rm -v=`pwd`:/defs $CONTAINER -f test/test.proto -s Message
docker run --rm -v=`pwd`:/defs $CONTAINER -f test/test.proto -i . -s Message

# And make sure that we can build the test gateway too.
docker build -t $CONTAINER-test-gateway gen/grpc-gateway/

# Now run the test container with a prefix in the background
docker run -p=8080:80 -e 'MESSAGE_PROXY_API-PREFIX=/api/' -e 'MESSAGE_RESPONSE-HEADERS_'${SOME_RESP_HEADER}'=some-value' $CONTAINER-test-gateway &

# Give it a few to start accepting requests
sleep 5

# Now use curl to make sure we get an expected status.
# From https://superuser.com/a/442395
status=`curl -i -s -o $HEADERS_FILE -w "%{http_code}" localhost:8080/api/messages`

# For now, we expect a 503 service unavailable, since we don't have a grpc service
# running. In the future, if this was a real backend we should get a 200. However,
# here we can use the 503 to indicate that the gateway tried to send the request
# downstream.
if [ "$status" -ne "503" ]; then
kill $!
echo "Invalid status: '$status' with /api/messages http request"
exit 1
fi

if ! grep -qi "$SOME_RESP_HEADER" "$HEADERS_FILE"; then
kill $!
echo "header $SOME_RESP_HEADER was not found in response"
rm $HEADERS_FILE
exit 1
fi
rm $HEADERS_FILE

# If we call an endpoint that does not exist (say just messages), we should
# get a 404, since there's no handler for that endpoint.
status=`curl -s -o /dev/null -w "%{http_code}" localhost:8080/messages`
if [ "$status" -ne "404" ]; then
kill $!
echo "Invalid status: '$status' with /messages http request"
exit 1
fi

# UnboundUnary should not work
# Unbound methods require the request payload as request body (curl --data 'payload')
status=`curl -s -o /dev/null -w "%{http_code}" --data '{}' localhost:8080/api/Messages.Message/UnboundUnary`
if [ "$status" -ne "404" ]; then
kill $!
echo "Invalid status: '$status' with /api/Messages.Message/UnboundUnary http request"
exit 1
fi

kill $!



# Test building the gateway with unbound methods.
docker run --rm -v=`pwd`:/defs $CONTAINER -f test/test.proto -i . -s Message --generate-unbound-methods

# And make sure that we can build the test gateway too.
docker build -t $CONTAINER-test-gateway gen/grpc-gateway/
Expand All @@ -33,10 +90,19 @@ status=`curl -i -s -o $HEADERS_FILE -w "%{http_code}" localhost:8080/api/message
# downstream.
if [ "$status" -ne "503" ]; then
kill $!
echo "Invalid status: '$status'"
echo "Invalid status: '$status' with /api/messages http request"
exit 1
fi

# UnboundUnary should work
# Unbound methods require the request payload as request body (curl --data 'payload')
status=`curl -i -s -o $HEADERS_FILE -w "%{http_code}" --data '{}' localhost:8080/api/Messages.Message/UnboundUnary`

if [ "$status" -ne "503" ]; then
kill $!
echo "Invalid status: '$status' with /api/Messages.Message/UnboundUnary http request"
exit 1
fi

if ! grep -qi "$SOME_RESP_HEADER" "$HEADERS_FILE"; then
kill $!
Expand All @@ -51,7 +117,7 @@ rm $HEADERS_FILE
status=`curl -s -o /dev/null -w "%{http_code}" localhost:8080/messages`
if [ "$status" -ne "404" ]; then
kill $!
echo "Invalid status: '$status'"
echo "Invalid status: '$status' with /messages http request"
exit 1
fi

Expand Down
2 changes: 2 additions & 0 deletions gwy/test/include.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ syntax = "proto3";

package Messages;

option go_package = "test/;test";

message ListMessageResponse {
repeated string messages = 1;
}
Expand Down
8 changes: 7 additions & 1 deletion gwy/test/test.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ syntax = "proto3";
package Messages;

import "google/api/annotations.proto";
import "include.proto";
import "test/include.proto";

option go_package = "test/;test";

service Message {
rpc ListMessage (ListMessageRequest) returns (ListMessageResponse) {
option (google.api.http) = {
get: "/messages"
};
}
rpc UnboundUnary (UnboundUnaryRequest) returns (UnboundUnaryResponse) {}
}

message ListMessageRequest {
string query = 1;
}

message UnboundUnaryRequest {}
message UnboundUnaryResponse {}

0 comments on commit 1c2146e

Please sign in to comment.