How to POST data to Confluence page using REST API and nodeJs,ExpressJs

Hi Atlassian Devellopers ,
i am develloping a Macro in add-on on confluence cloud , i am using nodeJS and ExpreeJs and i want to add PROPERTY called “spgviewspage”
to the meta-data of a confluence page with ID equal to pageId ( i get it via GET methode using rest api call )
i didn’t find a clearly documentation that describe : how the POST methode for sending Data it can be , contrariwise i found a tutorial which explain the GET methode here is the link: https://developer.atlassian.com/confcloud/lesson-2-rise-of-the-macros-39987235.html , so i tried to impliments a post methode bellow using the same concept.

getHTTPClient(clientKey,userKey).post('/rest/api/content/pageId/property/',function (req, res) {
var con=JSON.stringify(res)//valeur JavaScript en chaîne JSON
var newViwspage = {"key":"spgviewpages","value":0};
req.send(JSON.stringify(newViwspage));

but it display me an error message "req.send is not a function "
i am stack in this for more than a week i realy need #HELP
Reagrds Basma

Hi Basma,
My understanding is you like to create a property on a page. Although you were correct to post to property resource, you probably should check the way you did for posting.
Here is a good example in the READ.ME
https://bitbucket.org/atlassian/atlassian-connect-express/
Search for “How to send a signed outbound HTTP request back to the host”
or
“httpClient.post({”

Thnks for respending @zwang

I did just like the link u send it to me so :

FirstofAll
I tried this one (mounth a go ) wich has the same concept as the link u gave it to me after modifying “scopres” field in descriptor from only “READ” to “READ”,“WRITE”
and i also added (in the descriptor also) this field “renderingMethod”: “POST”, according to this tutorial in the link bellow
https://developer.atlassian.com/static/connect/docs/latest/modules/confluence/static-content-macro.html

//*********Solution 1

function getHTTPClient (clientKey, userKey){
    return addon.httpClient({
        clientKey : clientKey,
        userKey   : userKey,
        appKey    : addon.key
    });
}
    getHTTPClient(clientKey,userKey).post('/rest/api/content/pageId/property/',function (request, res) {
      var con=JSON.stringify(res)//valeur JavaScript en chaîne JSON
      var newViwspage = {"key":"spgviewpages","value":0};
     req.post(JSON.stringify(newViwspage));
     })

and it shows me this error message “req.send is not a function”
Second solution : according wish it seems to me more logical

//**********Solution 2

var newViewspage = {"key":"spgviewpages","value":0};
getHTTPClient(clientKey,userKey).post('request', function(request,res){
     request({
    url: 'rest/api/content/pageId/property/',
    data:  JSON.stringify(newViewspage),
    success: (data) => {
        console.log(data);
    },
    error: (err) => {
        console.log(err);   
    }
  });

});

but it shows me also an error but different message “request is not defined”

Reagards
Basma Held`Preformatted text```

Hi Basma,
There is something wrong in how you used post in your code. post function takes data object and a callback for the result of the post. Its signature is function(err, httpResponse, body).

httpClient.post({
            url: 'post url here',
            headers: {
                'X-Atlassian-Token': 'nocheck'
            },
            multipartFormData: {
                file: [data, { filename: 'some.png' }]
            }
        },
        function (err, httpResponse, body) {
            if (err) {
                return console.error('Upload failed:', err);
            }
            console.log('Upload successful:', body);
        });

Basically there are two ways you can call host api, one is using client side javascript = calling api directly from iframe = using javascript API. The other way is using server side javascript = httpClient. I saw you have tried both, but unfortunately your syntax was wrong in both cases.

Hi @zwang

Understood ,But this is to add a file not a property , so i tried to adapt what you give to me for what i want to have like the code below


app.get('/v1/RenderInformationBox',addon.authenticate(),  function(req,res){

    //  Grab all input parameters - sent through to us as query params.
    var 
        pageId      = req.query['pageId'],
        pageVersion = req.query['pageVersion'],
        macroHash   = req.query['macroHash'],
       userKey     = req.query['user_key'];
    clientKey = req.context.clientKey;





function getHTTPClient (clientKey, userKey){
    return addon.httpClient({
        clientKey : clientKey,
        userKey   : userKey,
        appKey    : addon.key
    });
}
getHTTPClient.post({
            url: 'rest/api/content/pageId/property/',
            headers: {
                'X-Atlassian-Token': 'nocheck'
            },
            multipartFormData: {
                file: [{"key":"spgviewpages","value":0}, { filename: 'some.png' }]
            }
        },
        function (err, httpResponse, body) {
            if (err) {
                return console.error('Upload failed:', err);
            }
            console.log('Upload successful:', body);
        });
}//fin test
});
}

But i stuck in the part of multipartFormData and in my case what i should write ?
Regards
HELD Basma

 httpClient.post({
                    url: 'rest/api/content/12345/property',
                    headers: {
                       'X-Atlassian-Token': 'nocheck'
                    },
                    json: {
                      "key" : "myprop", 
                      "value" : {
		         "anyKey" : "anyValue"
		       }
                    }
                }, function(err, callbackRes, body) {
                     console.log( "body:" + JSON.stringify(body) + "   callbackRes : " + JSON.stringify(callbackRes));
                });

Hi @zwang
Thank you so much for the piece of code you gave it to me , i tried and i have no errors but when i check: if the property is set to the list of page properties or no , i found that It has not been added :frowning: .
so i tried to display those three parameters : err, callbackRes and body as it shows the code bellow ( console.log …)

    function viewsPageNember(){
console.log("********************************begin of  POST method *********************************")
 getHTTPClient(clientKey,userKey).post({
                    url: '/rest/api/content/pageId/property/',
                    headers: {
                       'X-Atlassian-Token': 'nocheck'
                    },
                    json: {
                      "key" : "spgviewpages", 
                      "value" : {
             "anyKey" : "anyValue"
           }
                    }
                }, function(err, callbackRes, body) {
                    console.log( "body:" + JSON.stringify(body) + "   callbackRes : " + JSON.stringify(callbackRes));
             console.log("******************************** began of POST method *********************************\n")
 console.log("********************************error on the  client********************************* \n "+err)
       console.log("********************************error on the server ********************************* \n"+body)
  console.log("********************************error on the server********************************* \n"+JSON.parse(body))
   console.log("********************************error on the  callbackRes********************************* \n"+JSON.parse(callbackRes))
console.log("\n \n \n ********************************End of POST method ********************************* \n")
                });
}

to find the source of error so this is what i get in the console

******************************** began of POST method *********************************

********************************error on the  client*********************************
 null
********************************error on the server *********************************
undefined
undefined:1
undefined
^

SyntaxError: Unexpected token u in JSON at position 0
    at Object.parse (native)
    at Request._callback (D:\PFE_Stage\ideation-cloud\routes\index.js:97:110)
    at Request.self.callback (D:\PFE_Stage\ideation-cloud\node_modules\request\request.js:188:22)
    at emitTwo (events.js:106:13)
    at Request.emit (events.js:191:7)
    at Request.<anonymous> (D:\PFE_Stage\ideation-cloud\node_modules\request\request.js:1171:10)
    at emitOne (events.js:96:13)
    at Request.emit (events.js:188:7)
    at IncomingMessage.<anonymous> (D:\PFE_Stage\ideation-cloud\node_modules\request\request.js:1091:12)
    at IncomingMessage.g (events.js:291:16)
    at emitNone (events.js:91:20)
    at IncomingMessage.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:974:12)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)
    at process._tickCallback (internal/process/next_tick.js:98:9)

I apreciate your #Help
Regards
BASMA HELD

HI, I tested this code again today, and it worked in my instance. Can you make sure:

    app.get('/myByline', addon.authenticate(), function (req, res) {
            var httpClient = addon.httpClient(req);
            httpClient.post({
                    url: 'rest/api/content/233247/property',
                    headers: {
                        'X-Atlassian-Token': 'nocheck'
                    },
                    json: {
                        "key" : "myprop",
                        "value" : {
                            "anyKey" : "anyValue"
                        }
                    }
                },
                function (err, callbackRes, body) {
                   console.log(err);
            });
...
}
  1. You have valid pageId used in your url, because from your code it looks it is a hard coded string ‘pageId’.
  2. You addon descriptor (atlassian-connect.json) must have WRITE in scope.
  3. After you change descriptor, you always have to reinstall addon on your test instance.

If you still cannot get it to work, please try to run your addon in debug mode, then step through and inspect the error and body returned in callback. That error message will give more information.

1 Like

Hi zwang ,
it works ! , and i am realy greatful for that , but after Posting that property i need to update it ( i want to update the value of “views” field in my code ,or in your code called is “anyValue” field ),
so How can i do that ? #Need_Help_Please .

for more information you can read what i wrote below :
knowing that I tried with PUT method ( like it shows the code bellow )with same concept of POST method but didn’t work
Explication of the code : i tried to read the value of “views” field via GET method and if it exist i update it with PUT method if not (doesnt exist ) i create it.

 getHTTPClient(clientKey, userKey).get('/rest/api/content/'+pageId+'/property',
        function(err, response, contents){
         
            if(err || (response.statusCode < 200 || response.statusCode > 299)) {
                  
                      res.render('RenderInformationBox', { nbre : contents.size, pageId : pageId  });
                          
            }
        
          contents = JSON.parse(contents);
          if (contents.size !==0 )

          { if(contents.results[0].value.hasOwnProperty("views"))
          {
            console.log("already exist")
            var x=contents.results[0].value.views          
           var nbrvs = parseInt(x)
            nbrvs=nbrvs+1;
            var res = nbrvs.toString()
            
            //**********************************
               var httpClient = addon.httpClient(req);
            httpClient.put({
                    url: 'rest/api/content/'+pageId+'/property',
                    headers: {
                        'X-Atlassian-Token': 'nocheck'
                    },
                    json: {
                        "key" : "spg-idea-data",
                        "value" : {
                            "views" : res
                        }
                    }
                },
                function (err, callbackRes, body) {
                   console.log(err);
            });

            //**********************************
          }
         
        }
          else
            {

               var httpClient = addon.httpClient(req);
            httpClient.post({
                    url: 'rest/api/content/'+pageId+'/property',
                    headers: {
                        'X-Atlassian-Token': 'nocheck'
                    },
                    json: {
                        "key" : "spg-idea-data",
                        "value" : {
                            "views" : 0
                        }
                    }
                },
                function (err, callbackRes, body) {
                   console.log(err);
            });
            }
        }
    );

Regards
HELD Basla

Good news Basla! That is music to my ears!

I think you forgot to bump up the version number when you update property. This is required as it is mentioned in REST API Doc https://docs.atlassian.com/confluence/REST/latest/#content/{id}/property-update

Hi @zwang
I read what’s mention in the link you gave to me
so i add the name of the property in the URL of the put method but i am not sure if i did the right thing because the property has not been updated :frowning: ,
here is the PUT method and i want to update the “views” field (in your exemple is “anyKey” field )

 var httpClient = addon.httpClient(req);
            httpClient.put({
                    url: 'rest/api/content/'+pageId+'/property/spg-idea-data',
                    headers: {
                        'X-Atlassian-Token': 'nocheck'
                    },
                    json: {
                        "value" : {
                            "views" : 7
                        }
                    }
                },
                function (err, callbackRes, body) {
                   console.log(err);
            });

knowing that the property is defined like this via POST method

json: {
                        "key" : "spg-idea-data",
                        "value" : {
                            "views" : 0
                        }
                    }

Regards
Basma HELD

Hi again @zwang

this property "spg-idea-data"is posted well like in the Json bellow with value equal “0”

{
    "results": [
        {
            "id": "1337272",
            "key": "spg-idea-data",
            "value": {
                "views": 0
            },
            "version": {
                "when": "2017-05-26T17:49:55.078+01:00",
                "message": "",
                "number": 1,
                "minorEdit": false
            },
            "_expandable": {
                "content": "/rest/api/content/1337196"
            },
            "_links": {
                "self": "https://ideationcloud.atlassian.net/wiki/rest/api/content/1337196/property/spg-idea-data"
            }
        }
    ],
    "start": 0,
    "limit": 10,
    "size": 1,
    "_links": {
        "base": "https://ideationcloud.atlassian.net/wiki",
        "context": "/wiki",
        "self": "https://ideationcloud.atlassian.net/wiki/rest/api/content/1337196/property/"
    }
}

So i tried to update it to a value equal for “2” so i did that

app.get('/v1/RenderInformationBox', addon.authenticate(), function (req, res) {
 var httpClient = addon.httpClient(req);
            
            httpClient.put({
                    url: 'rest/api/content/1337196/property/spg-idea-data',
                    headers: {
                        'X-Atlassian-Token': 'nocheck'
                    },
                    json: {
                         
                          "value" : {
                            "views" : 2  }
                        }
                    
                },
                function (err, callbackRes, body) {
               console.log("this is what contain err "+err);
            console.log(" this is what contain callbackRes"+callbackRes)
            console.log("this is what contain body "+body)

            });

             });

But the property has not been modified so i displayed in the console thisThe three parameters err callbackRes and body (may be it helps) to know from where the error came

this is what contain err null
 this is what contain callbackRes[object Object]
this is what contain body [object Object]

#HELP
Regards
BASMA HELD

Hi, I believe you have not constructed the json body correctly. Please try this:

json: {
    "key": "spg-idea-data",
    "value": {
        "views": "7" << I presume this is the value you wanted to set.
    },
    "version": {
        "number": 2, << Must increment version number by 1, it was 1 when property was created.
        "minorEdit": false
    }
}

In our document it explained you must include property key AND version. Version starts from 1.
Regards
Ziming

@zwang
well done it works ! , i realy apreciate it ^^ , but i must increment the number of version by 1 each time when i want to update the property or just for the first update ?

1 Like

Yes, each time!
In Confluence, property is treated just like normal Content, which is versioned and searchable.

1 Like

Hello @zwang,

Understood ^^ ,
Thanks for mention that , and i am sorry for replying late , can you give me the source ? : where you find this kind of documentation (which explained for example that i must include property version ) cause i didnt find it in Atlassian Documentation (in case if i stuck in another issue in the future)

Regards
HELD Basma

https://docs.atlassian.com/confluence/REST/latest/#content/{id}/property-update

You must increment the the version number for each property correctly.

1 Like