Client
Client is one of the core features of gRPCity
, mainly providing the ability to obtain services and make RPC calls.
Initialization
const clients = await loader.initClients({ services, channelOptions, credentials })
Parameter explanation:
services
: Required,{ [service name]: address }
[service name]
: Service name with package name;address
: Server communication address, supports two formats, such as:host:port
or{ host, port }
channelOptions
: Optional, communication configuration rules;credentials
: Optional, client-side certificate;
Example:
const credentials = loader.makeCredentials(rootCerts, privateKey, certChain, verifyOptions)
const clients = await loader.initClients({
services: {
'dev.path.to.serviceA': 'domain.local:9099',
'path.to.serviceB': {
host: '192.168.32.111',
port: 10099
}
},
channelOptions,
credentials,
})
Middleware
clients.use()
provides middleware capabilities for pre and post-processing of call method
. For more details, see Middleware Guide
// Implementation of middleware support
// Add one by one
clients.use(f1)
clients.use(f2)
clients.use(f3)
// Add with multiple parameters
clients.use(f1, f2, f3)
// Add using an array
clients.use([f1, f2, f3])
Note: The current version only supports middleware for async
methods; callback
is not supported for now.
Get Instance
Obtaining instances here is relatively simple, just call get(name)
, and make sure to pass the complete service name
, including the package name.
const serviceAClient = clients.get('dev.path.to.serviceA')
const serviceBClient = clients.get('path.to.serviceB')
Note: get()
caches the client to ensure that when you retrieve the same client, it won’t be recreated, reducing resource consumption. getReal()
provides a way to get a client without caching.
RPC Call
There are two methods for making RPC calls, async
and callback
. In normal cases, we mostly use the async
syntax.
async
Here, we directly use the async/await
syntax.
const result = await serviceAClient.rpcMethod(request, metadata, options)
rpcMethod
(Method to call): This is a method for making requests. The method depends on therpc
defined in the.proto
file of the gRPC service, with 4 forms: unary, client streaming, server streaming, and bidirectional streaming;request
(Request parameters): This is an object containing the request data. The structure of the request object depends on the message type defined in the.proto
file of the gRPC service;metadata
(Metadata): This is an optional parameter used to pass metadata related to the request. Metadata is represented as key-value pairs and can contain data for authentication, authorization, tracking, or other purposes;options
(Options): This is an optional parameter used to set specific call options. It is an object containing a set of key-value pairs that can be used to configure the behavior of the call. Some available options include timeout, retry strategy, etc. If not passed, a default timeout of 10 seconds will be set, and you can modify the timeout by passing intimeout
;
Here is an example of a unary call:
const meta = loader.makeMetadata({
'x-business-id': ['grpcity', 'testing'],
'x-timestamp-client': 'begin=' + new Date().toISOString()
})
const options = {
timeout: 5000 // Represents a timeout 5 seconds from the current time.
}
const { status, peer, metadata, response } = await serviceAClient.rpcMethod({ name: 'myapp' }, meta, options)
After the client
initiates the request, the result received contains three values: status
, metadata
, and response
.
status
: The status after the server processes the execution;peer
: Client address information;metadata
: Metadata information returned by the server;response
: Result responded by the server after processing is complete;
The returned result example:
{
status: {
code: 0,
details: 'OK',
metadata: Metadata { internalRepr: Map(0) {}, options: {} }
},
peer: '::9098',
metadata: Metadata {
internalRepr: Map(2) { 'content-type' => [Array], 'date' => [Array] },
options: {}
},
response: { message: 'hello greeter by Greeter in server1', count: 1 }
}
callback
Making a callback
call requires adding an additional prototype chain, such as .call.
.
const a = serviceAClient.call.rpcMethod1({ name: 'myapp' }, (err, result) => {
if (err) {
throw err
}
return result
})
const b = serviceBClient.call.rpcMethod2({ name: 'youapp' }, (err, result) => {
if (err) {
throw err
}
return result
})
Reinitialization
There are some scenarios that require us to reinitialize clients
, for example: when the server’s access address changes. The provided solution here is to first execute clear()
, and then execute init()
.
The principle is to clear all caches from the previous client initialization, then reexecute the initialization to generate new cache info. The complete example is as follows:
const clients = await loader.initClients({
services: {
'dev.path.to.serviceA': 'domain.local:9099',
'path.to.serviceB': {
host: '192.168.32.111',
port: 10099
}
}
})
clients.clear()
clients.init({
services: {
'dev.path.to.serviceA': 'domain.local:9088',
'path.to.serviceB': {
host: '192.168.32.112',
port: 10099
}
}
})
Note: clear()
must be executed before init()
, otherwise it will not take effect.