The goal is still to create a process which get a random cat picture and post it on a yammer group daily. Last week I tried with the Yammer connector available in MS flow but it does not support posting image as I explain in https://djynet.net/?p=945 . This time I decided to go one level deeper and us the Yammer REST API which support it.
Yammer REST API
We want to use the /messages POST REST call describe in the official REST API doc here: https://developer.yammer.com/docs/messages-json-post which mention the support of attachments “Yammer provides two methods to associate attachments with a message. Both make use of multi-part HTTP upload (see RFC1867)”.
To be able to post we need to Authentify our self with the yammer Oauth2 flow describe here: https://developer.yammer.com/docs/oauth-2. I don t want to detail it too much since it’s pretty standard but basically our server offers and /login route which redirect to yammer.com.
app.get('/login', (req, res) => { var aLoginUri = "https://www.yammer.com/oauth2/authorize?client_id=CN737QnN3TCu2ooY7U2rbA&response_type=code&redirect_uri=https://djynet.xyz/callback"; res.send(aLoginUri); console.log('Sent login URI response'); });
Then yammer.com call redirect back the user to our server on /callback route with a user token we can use from our server when querying the yammer.com API to post messages.
// OAuth2 endpoint (callback) app.get('/callback', (req, res) => { res.end() console.log('Received Oauth login callback with code ' + req.url); //Calling Oauth to authenticate the APP var aUriAuthent = "https://www.yammer.com/oauth2/access_token?client_id=CN737QnN3TCu2ooY7U2rbA&client_secret=" + aClientSecret + "&code=" + req.query.code + "&grant_type=authorization_code"; axios.post(aUriAuthent) .then((res) => { //console.log("Dumping response for debuging: " +res) //console.log("Dumping data from response for Debug: ", res.data) aAUthTest2 = res.data; }) .catch((error) => { console.error(error) }) });
Getting random cat picture
Of course there is an API for that 😉 https://thecatapi.com/ The API is free but you need to register to get a API KEY that you specify in your header when calling with ‘x-api-key’. The endpoint we need is https://api.thecatapi.com/v1/images/search that we call without any parameters and will give us a random cat url.
async function getCatUrl() { console.log('Entering getCatUrl'); var aCatUrl = "https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_November_2010-1a.jpg"; const aTemp = await axios.get("https://api.thecatapi.com/v1/images/search", { params: {}, headers: { 'x-api-key': aCatApiKey } }); aCatUrl = aTemp.data[0].url console.log('Existing getCatUrl with: ', aCatUrl); return aCatUrl; }
One note here is the use of async/await for us to “wait” the response of catApi before we can proceed and post our picture in the yammer room. I will not detail await/asynch….so many good doc already (google it)
Posting the image
We now have a token and a cat picture URL that we can use to post our message. This is the only complicated part of this whole project due to “Both make use of multi-part HTTP upload (see RFC1867)”. I find this NPM module which should make this process easier: https://www.npmjs.com/package/form-data that we can use to create the “multipart/form-data” and then give to another module to send it to Yammer API. Here is the form part
var formData = new FormData(); formData.append('attachment1', Request(aCatUrl));
Which is quite straightforward as explain in their readme. Then we pass the form to another node module to send
Axios
The first module I tried to use to post the REST call is AXIOS: https://www.npmjs.com/package/axios which we use to get the random cat picture. Nevertheless, the documentation of form-data to use AXIOS has a bug which I was unable to understand so I open a bug report and switch to another library than Axios. The bug has now been fixed by a documentation change: https://github.com/form-data/form-data/issues/439
Https
Instead of axios we can use the native HTTPS nodejs module describe here: https://nodejs.org/api/https.html and pass him our form:
// Patch header to add the key var aHeader = formData.getHeaders(); aHeader['Authorization'] = "Bearer " + aAUthTest2.access_token.token; var request = https.request({ method: 'post', host: 'www.yammer.com', //very dirty.... did not find a way to pass param otherwise :( path: '/api/v1/messages.json?body=Cat%20of%20the%20day%20&group_id=7799980032', headers: aHeader }); //send it formData.pipe(request);
Final touch
I added a secret key in the postcat route to ensure nobody else will use it to spam the room with cat
if (req.query.key !== aPostCatSecretKey) { console.log("Invalid key: ",req.query.key," - send back 401") res.sendStatus(401); }
And then I added a crontab to call our API everyday
0 1 * * * curl https://djynet.xyz/postcat?key=mysecretkey
All code is here: https://bitbucket.org/charly37/catyammer/src/master/
And the result: