Yammer REST API

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: