Search code examples
node.jsgrpcgoogle-smart-homegrpc-node

How to call the Home Graph API with gRPC on Node.js


Given the protocol buffers definition available at: https://github.com/googleapis/googleapis/blob/master/google/home/graph/v1/homegraph.proto

How can one call the Home Graph API RPC endpoint using gRPC on Node.js to multiplex concurrent API method calls over a single connection?


Solution

  • You can use @grpc-js in combination with Application Default Credentials to initialize the credentials.

    $ npm install @grpc/grpc-js
    $ npm install google-auth-library
    $ export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account-key.json
    
    const grpc = require('@grpc/grpc-js');
    const { GoogleAuth } = require('google-auth-library');
    
    async function getCredentials() {
      const sslCredentials = grpc.credentials.createSsl();
      const googleAuth = new GoogleAuth({
        scopes: 'https://www.googleapis.com/auth/homegraph'
      });
      const authClient = await googleAuth.getClient();
      const callCredentials = grpc.credentials.createFromGoogleCredential(
          authClient
      );
      const credentials = grpc.credentials.combineChannelCredentials(
          sslCredentials,
          callCredentials
      );
      return credentials;
    }
    

    Use google-proto-files with @grpc/proto-loader to load the Home Graph service protobuf definition with its dependencies.

    const protoLoader = require('@grpc/proto-loader');
    const protos = require('google-proto-files');
    
    async function getHomegraph() {
      const homegraphProto = await protoLoader.load(
          protos.getProtoPath('home/graph', 'v1', 'homegraph.proto'), {
            includeDirs: [protos.getProtoPath('..')]
          }
      );
      const homegraph = grpc.loadPackageDefinition(
          homegraphProto
      ).google.home.graph.v1;
      return homegraph;
    }
    

    And finally initialize client stubs to call the HomeGraphApiService methods.

    (async function() {
      const credentials = await getCredentials();
      const homegraph = await getHomegraph();
    
      const homegraphService = new homegraph.HomeGraphApiService(
          'homegraph.googleapis.com', credentials
      );
    
      homegraphService.sync({
        agentUserId: 'AGENT_USER_ID'
      }, function(err, result) {
        if (err) {
          console.error(err);
        } else {
          console.log(result);
        }
      });
    
      // homegraphService.query();
      // homegraphService.requestSyncDevices();
      // homegraphService.reportStateAndNotification();
      // homegraphService.deleteAgentUser();
    })();
    

    Note that by default the Channel implementation will reuse existing channels from a global pool if the parameters (address, credentials and options) are the same. You can alter this behavior with the grpc.use_local_subchannel_pool option.