Getting Started
This guide explains how to use protocol-grpc for building abstract gRPC interfaces.
Installation
Add the gem to your project:
$ bundle add protocol-grpc
Core Concepts
protocol-grpc has several core concepts:
- A
class Protocol::GRPC::Interfaceclass which defines gRPC service contracts with RPC methods, request/response types, and streaming patterns. - A
class Protocol::GRPC::Body::ReadableBodyclass which handles reading gRPC messages from HTTP request/response bodies with automatic framing and decoding. - A
class Protocol::GRPC::Body::WritableBodyclass which handles writing gRPC messages to HTTP request/response bodies with automatic framing and encoding. - A
class Protocol::GRPC::Middlewareabstract base class for building gRPC server applications. - A
class Protocol::GRPC::Callclass which represents the context of a single gRPC RPC call, including deadline tracking. - A
module Protocol::GRPC::Statusmodule with gRPC status code constants. - A
class Protocol::GRPC::Errorhierarchy for gRPC-specific error handling.
Integration
This gem provides protocol-level abstractions only. To actually send requests over the network, you need an HTTP/2 client/server implementation:
- Async::GRPC which provides asynchronous client and server implementations.
- Async::HTTP which provides HTTP/2 transport with connection pooling and concurrency.
Usage
Defining an Interface
class Protocol::GRPC::Interface defines the contract for gRPC services. RPC method names use PascalCase to match .proto files:
require "protocol/grpc/interface"
class GreeterInterface < Protocol::GRPC::Interface
rpc :SayHello, request_class: Hello::HelloRequest, response_class: Hello::HelloReply
rpc :SayHelloAgain, request_class: Hello::HelloRequest, response_class: Hello::HelloReply,
streaming: :server_streaming
end
Building a Request
Build gRPC requests using Protocol::GRPC::Methods and Protocol::GRPC::Body::WritableBody:
require "protocol/grpc"
require "protocol/grpc/methods"
require "protocol/grpc/body/writable_body"
# Build request body
body = Protocol::GRPC::Body::WritableBody.new(message_class: Hello::HelloRequest)
body.write(Hello::HelloRequest.new(name: "World"))
body.close_write
# Build headers
headers = Protocol::GRPC::Methods.build_headers(timeout: 5.0)
path = Protocol::GRPC::Methods.build_path("hello.Greeter", "SayHello")
# Create HTTP request
request = Protocol::HTTP::Request["POST", path, headers, body]
Reading a Response
Read gRPC responses using Protocol::GRPC::Body::ReadableBody:
require "protocol/grpc/body/readable_body"
# Read response body
readable_body = Protocol::GRPC::Body::ReadableBody.new(
response.body,
message_class: Hello::HelloReply
)
message = readable_body.read
readable_body.close
# Check gRPC status
status = Protocol::GRPC::Metadata.extract_status(response.headers)
if status != Protocol::GRPC::Status::OK
message = Protocol::GRPC::Metadata.extract_message(response.headers)
raise Protocol::GRPC::Error.for(status, message)
end
Server Middleware
Create a server middleware by subclassing Protocol::GRPC::Middleware:
require "protocol/grpc/middleware"
class MyMiddleware < Protocol::GRPC::Middleware
protected
def dispatch(request)
# Parse service and method from path
service_name, method_name = Protocol::GRPC::Methods.parse_path(request.path)
# Handle the request and return a response
# ...
end
end
Call Context
class Protocol::GRPC::Call provides context for a gRPC call:
require "protocol/grpc/call"
call = Protocol::GRPC::Call.new(request, deadline: deadline)
# Access request
call.request # => Protocol::HTTP::Request
# Check deadline
call.deadline.exceeded? # => false
# Access peer information
call.peer # => Protocol::HTTP::Address