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:portor{ 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 therpcdefined in the.protofile 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.protofile 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.