How to send a JSON payload with UrlFetchApp service?
Asked Answered
S

5

22

I'm trying to POST to a web service that is expecting to get JSON as payload using Google Apps Script. I'm using the following code:

var options =
{
  "method" : "post",
  "contentType" : "application/json",
  "headers" : {
    "Authorization" : "Basic <Base64 of user:password>"  
  },
  "payload" : { "endDate": "2012-06-03" }
};

var response = UrlFetchApp.fetch("http://www.example.com/service/expecting/json", options);

On the server side I'm getting the following error:

WARN [facade.SettingsServlet] 04 Jun 2012 15:30:26 - Unable to parse request body: endDate=2012-06-03
net.liftweb.json.JsonParser$ParseException: unknown token e

I'm assuming that the server is expecting to get

{ "endDate": "2012-06-03" }

instead of

endDate=2012-06-03

but I don't know how to make the UrlFetchApp do it.

Serviette answered 4/6, 2012 at 20:57 Comment(1)
maybe #38677076Uncork
D
22

I do not understand the server side error but the 'payload' parameter must be a string as specified here: https://developers.google.com/apps-script/class_urlfetchapp?hl=fr-FR#fetch.

try:

var options =
{
  "method" : "post",
  "contentType" : "application/json",
  "headers" : {
    "Authorization" : "Basic <Base64 of user:password>"  
  },
  "payload" : '{ "endDate": "2012-06-03" }'
};
Drub answered 5/6, 2012 at 8:50 Comment(8)
It is said about the payload in the link: "...It can be a String, a byte array, or a JavaScript key/value map. See example.". When I try your proposal I get Error code 400 from the server. I tried Utilities.jsonStringify as well with the same 400 response code.Serviette
But is the server side error message the same? Try capturing the request to see what the body looks like.Islean
The error message is different as I don't get the request to the server at all (400). I can't capture the request from the client side (Google Apps Script), and I don't see it passing the Tomcat. No track of it in the Tomcat logs.Serviette
Yes I was wrong you can send String, byte array, or js key/value map. But in your case I think you need to send a string. Try using this command after your fetch to capture the HTTP request sent by GAS: Logger.log(UrlFetchApp.getRequest("example.com/service/expecting/json", options).toSource());Drub
Thanks for the tip, but it doesn't show the body of the request. I got when using JsonStrigify: ({headers:{Authorization:"Basic ..."}, oAuthServiceName:"", useIntranet:false, payload:"{\"endDate\":\"2012-06-03\"}", oAuthUseToken:"", method:"post", contentType:"application/json", url:"http://www.example.com/service/expecting/json"})Serviette
and ... payload:"dueDate=2012-06-03"... when using the json (non '' or Stringify) version.Serviette
JSON.stringify is prefered over Utilities.jsonStringify. The later has issues with some ids that the former doesn't.Shakeup
Yes, this solved the problem. I still think that being able to "debug" the request would be a good idea. In line with the getRequest method. I had to use curl -v -i --user user:password -H "Content-Type: application/json" -X POST -d '{ "endDate": "2012-06-03"}' http://example.com/service/expecting/json to be able to check the request format and the response content. From the GAS interface I couldn't do it.Serviette
C
3
  • If you set payload as a String, it will be passed directly (as a UTF-8 string).
  • If you set payload as an Object, it will be sent like an HTML form (which means either 'application/x-www-form-urlencoded' if the fields are simple, or 'multipart/form-data' if the Object includes a blob/file).

For your use case (the server is expecting to receive JSON), it sounds like Utilities.jsonStringify() is the way to go.

Cotswolds answered 6/6, 2012 at 14:45 Comment(2)
I suspect that there might be an issue with GAS in this scenario as the body of the request in this case is invalid in some way. The server that is usually parsing JSON in the body from other sources, is unable to parse the incoming request from GAS. I tried both versions of Stringing the payload, with '...' and Utilities.jsonStringify(...).Serviette
Maybe to compare the requests, try the POST to an echo URL like: responseecho.appspot.comCotswolds
M
1

My variant. Thanks to book by Bruce Mcpherson "Going GAS From VBA to Google Apps Script"

var options =
{
  method : "POST",
  contentType : "application/json",
  headers : {
    Authorization : "Basic <Base64 of user:password>"  
  },
  payload : JSON.stringify({"endDate":"2012-06-03"})
};
Mcnabb answered 1/6, 2023 at 6:7 Comment(0)
P
-1

Something like this worked for me in a similar situation:

Instead of creating payload and adding to options, I built the parameters into a string to append to the URL:

var params = "id=2179853&price=62755";

then, I appended params to the url string:

var result = UrlFetchApp.getRequest(url + '?' + params, options);

So, my options was passed containing only the header.

For my project, this worked like a charm.

Piecrust answered 8/11, 2019 at 20:21 Comment(0)
A
-2

Here goes the code that should work with some important comments:

function testMe() {
    var products_authkey = "------------";
    try {
        var url = "https://app.ecwid.com/api/v1/---------/product?id=----------&secure_auth_key=" + products_authkey;
        //url= "http://requestb.in/----------"; // you can actually debug what you send out with PUTs or POSTs using Requestb.in service
        var payload = {
            id: "21798583", // id is necessary and should be a string, or it might be sent in scientific representation (with E)
            price: 62755
        }; 

        payload = JSON.stringify(payload); // the payload needs to be sent as a string, so we need this
        var options = {
            method: "put",
            contentType: "application/json", // contentType property was mistyped as ContentType - case matters
            payload: payload
        }; 
        var result = UrlFetchApp.getRequest(url, options);
        Logger.log(result) // a better way to debug
        var result = UrlFetchApp.fetch(url, options); // works perfectly in my case
        Logger.log(result)
    } catch (e) {
        Logger.log(e)
    }
}
Alisander answered 17/9, 2013 at 13:20 Comment(1)
Should be JSON.stringify(payload)Gladi

© 2022 - 2024 — McMap. All rights reserved.