Closed Abhi347 closed 5 years ago
👋 greetings! There are a few good reference docs you can use for Chat. FIrst, here's the developer guide: https://developers.google.com/hangouts/chat/
And for a reference of how to use the API: http://google.github.io/google-api-nodejs-client/modules/_apis_chat_v1_.html
Does this get you where you need to go? Or are there are specific things you're looking for? Hope this helps!
Hi Justin, thanks for replying. I have the Chat API working using the REST API, but I was looking for the documentation of the node.js client, just like how I use sheets API. I tried using the nodejs client, but it started giving me some strange errors. Let me recreate them - Here's my code, just to give you an idea
/* eslint-disable no-console */
const url = require('url');
const request = require('request-promise-native');
const CHAT_ENDPOINT = 'https://chat.googleapis.com';
async function sendMessageUsingRestApi(apiKey, threadName, message) {
let threadParts = threadName.split('/');
let spaces = threadParts[1];
let threadKey = threadParts[3];
const auth = apiKey;
let endPointUrl = url.resolve(
CHAT_ENDPOINT,
`/v1/spaces/${spaces}/messages?threadKey=${threadKey}&key=${auth}`
);
const chatApiResponse = await request.post(endPointUrl, {
json: { text: message }
});
return chatApiResponse;
}
const { google } = require('googleapis');
const chat = google.chat('v1');
const { promisify } = require('util');
chat.spaces.messages.createAsync = promisify(chat.spaces.messages.create);
async function sendMessageUsingClient(apiKey, threadName, message) {
let threadParts = threadName.split('/');
let spaces = threadParts[1];
let threadKey = threadParts[3];
const auth = apiKey;
const chatApiResponse = await chat.spaces.messages.createAsync({
auth: auth,
parent: `spaces/${spaces}`,
threadKey: threadKey,
body: {
text: message
}
});
return chatApiResponse;
}
sendMessageUsingRestApi(
'MY_API_KEY',
'spaces/<spaceID>/threads/<threadKey>',
'Hi From Rest'
)
.then(response => console.log(response))
.catch(e => console.error(e));
sendMessageUsingClient(
'MY_API_KEY',
'spaces/<spaceID>/threads/<threadKey>',
'Hi From Client'
)
.then(response => console.log(response))
.catch(e => console.error(e));
So, the REST API works and I get the message Hi From Rest
in my chat window, however the nodejs client gives me error, just because it's not clear which parameter will go where. I have tried a lot and finally decided to use the REST API. The problem with that is, I have to use an API key, instead of the Service Account. That's why I think there should be a proper documentation of using Chat API using the Nodejs client.
Here's the error I am getting just in case it helps -
{Error: <h1>Not Found</h1>
<h2>Error 404</h2>
at createError (/Volumes/Projects/Work/node_modules/axios/lib/core/createError.js:16:15)
at settle (/Volumes/Projects/Work/node_modules/axios/lib/core/settle.js:18:12)
at Unzip.handleStreamEnd (/Volumes/Projects/Work/node_modules/axios/lib/adapters/http.js:201:11)
at emitNone (events.js:111:20)
at Unzip.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1055:12)}
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
I added the service authentication code to yours and the REST API call works well with it! Just make a service account and download the JSON credentials file and put it in your directory. However, I only got this to work with REST API call, if I make any further progress later, I can update this comment.
(I commented out the token check function because the callback function was giving me an issue)
`const fs = require('fs');
const readline = require('readline');
const {google} = require('googleapis');
const request = require('request-promise-native');
// If modifying these scopes, delete credentials.json.
const SCOPES = ['https://www.googleapis.com/auth/script.projects'];
const TOKEN_PATH = 'credentials.json';
// Load client secrets from a local file.
fs.readFile('client_secret.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
// Authorize a client with credentials, then make the REST API call.
authorize(JSON.parse(content), sendMessageUsingRestApi('<API key>','spaces/<space ID>','This is sent using REST API'));
});
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
* @param {Object} credentials The authorization client credentials.
* @param {function} callback The callback to call with the authorized client.
*/
function authorize(credentials, callback) {
const {client_secret, client_id, redirect_uris} = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]);
/*
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) {
return getAccessToken(oAuth2Client, callback);
}
oAuth2Client.setCredentials(JSON.parse(token));
if(callback){
callback(oAuth2Client);
}
});
*/
}
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
* @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
* @param {getEventsCallback} callback The callback for the authorized client.
*/
function getAccessToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
});
console.log('Authorize this app by visiting this url:', authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question('Enter the code from that page here: ', (code) => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return callback(err);
oAuth2Client.setCredentials(token);
// Store the token to disk for later program executions
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) console.error(err);
console.log('Token stored to', TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}`
Thanks @lcundiff for the code. I would however really appreciate if we can make this work with the nodejs client also. I hope somebody just updates the docs somewhere.
I'm also having issues understanding the docs provided for Chat. Despite the auth issues which I've managed to work out elsewhere, I simply can't create a message and send to a space.
const chat = google.chat({version: 'v1', auth: jwtClient});
chat.spaces.messages.create({
parent: space.name,
body: {
text: 'hello world'
}
})
.then(res => {
console.log('Response:', res.data);
})
.catch(err => {
console.error('Error:', err);
});
Which throws:
Invalid JSON payload received. Unknown name "body[text]": Cannot bind query parameter. Field \'body[text]\' could not be found in request message.
The debug of the error says that the POST request is:
POST /v1/spaces/6WNdlAAAAAE/messages?body%5Btext%5D=hello%20world
without any POST body.
An example in a comment above used this body.text
item and it was reported to work but I can't see how it ever worked. Also, when I put that body.text
as the second argument to the create function, it complains that Message cannot be empty
.
There are numerous samples for other Google services, why not Chat?
To update anyone else looking for a solution to this, I dug deep in to the google source and discovered that the following create method signature works:
chat.spaces.messages.create({
parent: 'spaces/xxxxxx',
requestBody: {
text: 'hello world'
}
})
@jc21 Awesome. Have you done anything using the threadKey query parameter when creating a message? Trying to continuously update a message instead of sending new ones using messages.update (but it requires threadKey.
Found a work around. Just am using the message ID pulled from the message JSON. The thread ID is in the message JSON too, but realized thread ID is used for "replying" to a message while message ID (name attribute in the JSON) is used for updating! So only use threadID for using the chat reply feature.
I think this issue can be closed. We have some docs and samples like these ones: https://developers.google.com/hangouts/chat/reference/rest/ https://github.com/gsuitedevs/hangouts-chat-samples/tree/master/node
@JustinBeckwith Close this issue?
What comes after spaces in the Parent key Object @jc21 ? Can you help me please ?
Hangouts endpoints is real amateur hour for google.
3 years and there is still no working docs, you have to poke your way through the dark using 3 different sdk's to get a bot to do one thing.
I'm now 12 hours deep implementing a google chat bot, and I've just gotten it to send its first message, how long does this take with telegram/discord? under 60 seconds.
Closing this issue was a huge mistake, do we have to just thumbsuck that requestBody is needed for the node.js sdk to work? this is a sad sad day for google and their teams, I feel embarrassed that I recommended these services 6 years ago to these clients after this past year of VAS software implmentations, formats keep changing, services constantly get breaking changes, undocumented changes to security protocol, the docs are swiss cheese.
If anybody is scrolling through this thread concerning this issue and thinks the closed status means the discussion cant help you, please re-read this discussion, if you're getting message can not be empty errors and then errors when you try and fill in the text param, you need requestBody in your request object 🤦♀️🤦♂️
Hangout Chat API is supported in the latest client library, but there's no documentation for that. Can we have a documentation for Hangout Chat API too, especially for the asynchronous calls?