Skip to content

Client: Making Your First Call

Shaun McCormick edited this page Jun 17, 2019 · 3 revisions

From there, you can instantiate a client given a stub service (say on an Jobs service with a GetJob call):

require 'gruf'

id = args[:id].to_i.presence || 1

begin
  client = ::Gruf::Client.new(service: ::Demo::Jobs)
  response = client.call(:GetJob, id: id)
  puts response.message.inspect # This will output the ::Demo::GetJobResp object
rescue Gruf::Client::Error => e
  puts e.error.inspect # If an error occurs, this will be the underlying error object
end

Let's break this down a bit. First off, we'll create the client object. Note that you'll need to require the service stubs first before doing this. (We don't do so in this example, but you'll need to somehow, either through a gem or explicit require statement.) Also note that the service you specify in the client does not include the "::Service" postfix - Gruf will append that for you automatically.

client = ::Gruf::Client.new(service: ::Demo::Jobs)

Similarly to most client libraries, we'll create the client object, and this client will be bound to a specific service. We can provide more options here if we want, such as the hostname of the client (which defaults to whatever Gruf.default_client_host is, which is blank by default):

client = Gruf::Client.new(
  service: ::Demo::Jobs,
  options: {
    hostname: '0.0.0.0:9003',
    username: 'admin',
    password: 'password',
  }
)

Anything in options is optional, so you don't have to include a un/pw if you aren't serving the gRPC server with one (the un/pw here is for basic auth).

Once we've got our client, we'll make the call:

response = client.call(:GetJob, id: id)
puts response.message.inspect

The first argument is the protobuf name of the RPC all, and the second is a hash of arguments to send (essentially, the Request object - Demo::GetJobReq here - will be automatically determined and composed by the hash arguments here). This will return a response object of Gruf::Response, which contains various information and attributes that can be used to find out information about the response.

Most importantly, we're looking for the message, so here we can inspect response.message to see the Demo::GetJobResp object for our data. The response object also provides trailing_metadata as well as a execution_time, for further debugging.

Handling Errors

For failed calls, such as if the server returns a GRPC::BadStatus response using fail! or other failure methods, we'll want to handle that. Gruf::Client automatically does this by raising an appropriate Gruf::Client::Error class.

rescue Gruf::Client::Error => e
  puts e.error.inspect # If an error occurs, this will be the underlying error object

You'll immediately notice that Gruf::Client::Error is actually a base class - the error class will actually be a matching derivative of whatever GRPC::BadStatus code is being failed with. For example, a GRPC::NotFound error will end up being a Gruf::Client::Errors::NotFound error, and so forth. These extend Gruf::Client::Error, allowing you to catch specific errors or use a catch-all instead.

Error Deserialization

Note also that this will also deserialize anything in the Gruf.error_metadata_key if it's included in the trailing metadata, which can be used to pass around more detailed error information. Whatever error serializer is being used (configured via Gruf.error_serializer) will be used to deserialize this information, defaulting to JSON.


Next: Client: Interceptors