I'm trying to use Google Apps Scripts to post to Salesforce to create a new account. I'm able to use my credentials fine to query with SOQL. When I try to post, it basically returns data as if I'm describing the Account, and the new account doesn't get created. I tried using the workbench rest API with this payload and can create an account no problem, so I know it's not an issue with fields/values.
function pushToSalesforce(){
var userProperties = PropertiesService.getUserProperties();
var instance_url = "https://na9.salesforce.com";
var access_token = userProperties.getProperty('access_token');
var payload = {
"Name" : "testaccount",
"Website" : "testaccountstuff.com",
"Platform__c" : "API",
"Industry" : "Apparel"
};
var queryUrl = instance_url + '/services/data/v26.0/sobjects/account/';
var headers =
{
"method" : "POST",
"contentType" : "application/json",
"payload": JSON.stringify(payload),
"headers": {
"Authorization" : "Bearer "+access_token,
"Accept": "application/json"
}
};
var response = UrlFetchApp.fetch(queryUrl, headers);
}
I'm going nuts trying to figure out what the issue is. Anybody have an idea?
Sounds like your app is making a GET instead of POST. Is this language / HTTP library case-sensitive? Documentation seems to use lowercase
You are supposed to send a POST to /services/data/v49.0/sobjects/Account (you're using very old API version but that shouldn't matter). What exactly do you see in response? It may look "describe'ish" but it's unlikely to be a real describe result unless you explicitly call /services/data/v49.0/sobjects/Account/describe.
A GET call to /services/data/v49.0/sobjects/Account is a discovery, a way for the API to self-document. Returns very basic info about the object, something like
{
"objectDescribe" : {
"activateable" : false,
"createable" : true,
"custom" : false,
(... snip...)
"updateable" : true,
"urls" : {
"compactLayouts" : "/services/data/v48.0/sobjects/Account/describe/compactLayouts",
"rowTemplate" : "/services/data/v48.0/sobjects/Account/{ID}",
"approvalLayouts" : "/services/data/v48.0/sobjects/Account/describe/approvalLayouts",
"defaultValues" : "/services/data/v48.0/sobjects/Account/defaultValues?recordTypeId&fields",
"listviews" : "/services/data/v48.0/sobjects/Account/listviews",
"describe" : "/services/data/v48.0/sobjects/Account/describe",
"quickActions" : "/services/data/v48.0/sobjects/Account/quickActions",
"layouts" : "/services/data/v48.0/sobjects/Account/describe/layouts",
"sobject" : "/services/data/v48.0/sobjects/Account"
}
},
"recentItems" : [ ]
}
A proper describe call would instead return info about all columns you can see in the table, all relations (foreign keys) to this object...
In my actual script was the "my domain" custom instance_url for my company (but didn't want to broadcast it), e.g. "https://companyname.lightning.force.com". I tried using my server instance "na85" instead and it worked fine! Super weird because I have another function using the other instance_url with a GET and it worked no problem. Thanks for your help!
Related
I have a JSON request in the following structure-
{
"user_id" : "1",
"user_details" : {
"name" : "my_name"
"passport_image" : "passport_image.jpg"
},
"user_documents" : [
{"file" : "doc_1.jpg"},
{"file" : "doc_2.jpg"}
]
}
How can I send files via postman that are part of a JSON request?
This is what I tried -
But then passport_image.jpg would be its own field and not part of user_details object, correct?
And what about the array of file objects under user_documents? How can I send it too in the request?
I would appreciate help as I'm quite new to using form-data requests rather than raw JSON ones.
You can set the keys as array. It can be set like this. user_documents[0] and the respective file for it.
This will work!
The above answer is wrong, the way to do it is to select the key value = to the value you used in your code, for instance see below:
const storage = multer.diskStorage({
destination: function(req,file,cb) {
cb(null,'uploads/')
},
filename: function(res,file,cb) {
console.log('file= ',file)
const uniqueSuffix=Date.now()+'-'+Math.round(Math.random()*1e9)
cb(null, file.fieldname+'-'+uniqueSuffix+'.jpg')
}
})
const upload = multer({storage:storage})
app.post('/uploads', upload.array('files',12), (req,res)=>
{
req.files.map((file)=>{
console.log('received request: ', file)
})
res.status(200).send('received files')
})
Then in postman you just select several files, in this case less than 12 after clicking on the select files button. Just one entrance for multiple files.
Actually I find solution on Youtube. You can choose multiple files by keeping Ctrl and choose multiple files.
I'm using Vimeo's official NodeJS API module to build an app, and I can successfully upload a video without issue. I can also set the video's privacy property successfully. Now, I would like to move that uploaded video to an album, and if the album does not exist, I want to create one automatically. I have an access token stored in a file that my application reads from, and the scopes granted to the token are the following
"scope": "interact create edit upload delete video_files private public"
So, I've got the create scope which is needed to create a new album for a user. However, when I make the request to the Vimeo API, I am getting an error of which I cannot resolve or fix.
{
"invalid_parameters":[{
"field":"name",
"error_code":2204,
"error":"You have provided an invalid parameter. Please contact developer of this application.",
"developer_message":"The parameters passed to this API endpoint did not pass Vimeo's validation. Please check the invalid_parameters list for more information."
}]
}
Here is my code that is making the request:
if (!album_uri) {
console.log("Attempting to create a new album named `" + config.params.video.group + "`");
var req_make_album = {
"method" : "POST"
, "path" : "/me/albums"
, "name" : config.params.video.group
, "description" : config.params.video.group
};
api.request(req_make_album, function(error, body, status_code, headers) {
if (error)
throw new Error(error);
step();
})
}
To be sure, the config.params.video.group variable is a string and to be certain that it was in fact a string, I replaced the request options with literal ones as such:
var req_make_album = {
"method" : "POST"
, "path" : "/me/albums"
, "name" : "My First New Album"
, "description" : "My First New Album"
};
Still, I received the above error about the "name" field being invalid. What am I missing here? When I go to the Vimeo API "playground" for this particular endpoint, it does work (even when I authenticate via my app) but I don't understand why it won't work when I make the request via the NodeJS module. Why am I getting this error?
My mistake. The issue is that the Vimeo API requires that the items "name" and "description" to be passed as an object.
So, instead of
var req_make_album = {
"method" : "POST"
, "path" : "/me/albums"
, "name" : "My First New Album"
, "description" : "My First New Album"
};
It should actually be:
var req_make_album = {
"method" : "POST"
, "path" : "/me/albums"
, "query" : {"name" : "My First New Album", "description" : "My First Album's Description"
};
The more you know :)
So I have the jQuery datatable using AJAX to call for the JSON in this format.
$(document).ready(function () {
$('#test').DataTable({
ajax:{
url:"players.json",
dataSrc:""
},
columns: [
{data: "id"},
{ data: "player" },
{ data: "points" },
{ data: "steals" },
{ data: "blocks" },
{ data: "assists" },
{ data: "MPG" },
{ data: "shot %" },
{ data: "3 %" }
]
});
});
My aspx.cs file has a method to create the JSON file which works.
[System.Web.Services.WebMethod]
public static void loadTable()
{
NBAPlayerRepository players = new NBAPlayerRepository();
DataTable dt = players.GetAll();
var json = dt.ToJson();
System.IO.File.WriteAllText(#"C:\Users\wheres\Downloads\nbaStats\nbaStats\nbaStats\players.json", json);
}
And the JSON looks like this:
[{"id" : "67926aa7-46b7-4418-96db-fc7e5216aac4","playername" : "Wilson Heres","points" : "34534","steals" : "34","blocks" : "34","assists" : "343","mpg" : "343","shootingpercentage" : "33.3429985046387","threepointpercentage" : "33.3429985046387"}
,{"id" : "6dc42e0b-8750-463d-a9ef-5a025a27154b","playername" : "Wilson Heres","points" : "34534","steals" : "34","blocks" : "34","assists" : "343","mpg" : "343","shootingpercentage" : "33.3429985046387","threepointpercentage" : "343.334014892578"}
,{"id" : "f727130c-5b94-4730-a653-cfb603c73b8a","playername" : "Wilson Heres","points" : "34534","steals" : "34","blocks" : "34","assists" : "343","mpg" : "343","shootingpercentage" : "33.3429985046387","threepointpercentage" : "343.334014892578"}
]
But now I am getting this error "jquery.dataTables.min.js:48 Uncaught TypeError: Cannot read property 'length' of undefined"
Edit: This all works now. Just had to add dataSrc:""
Cleaned-up version of your DataTables initialization
$(document).ready(function () {
$('#test').DataTable({
ajax: {
url: "players.aspx/loadTable"
},
columns: [
{ data: "id" },
{ data: "player" },
{ data: "points" },
{ data: "steals" },
{ data: "blocks" },
{ data: "assists" },
{ data: "MPG" },
{ data: "Shot %" },
{ data: "3 %" },
]
});
});
This may seem like a lot of stuff was removed from your code, so let me make some explanations/assumptions about what was changed.
Assumptions
First, an assumption: DataTables will always try to use a GET request, not a POST when first getting the data from the table, so make sure that your data processing code expects that.
I also am assuming that you have no strong desire to have your Ajax separate from your initialization and that was just how you decided to do it as a first attempt. If that is the case, let me know and I'll update the code to match that.
Explanation
Your formatting is incorrect in some areas and against DataTables standard in others, so this version should do most of what you were trying to do in a much simpler form. A lot of your Ajax options are unnecessary because they are already the default (JSON for the data type, for example), which is why they have been removed.
One nice thing about DataTables is that you can have the Ajax options in the initialization, which is what I have done here. You do lose the success and failure callbacks but I think that for debugging purposes they aren't really necessary and having any extra code increases the amount of stuff to debug (I don't even use those callbacks in most of my final code).
Most of the other changes were mainly incorrect nomenclature (e.g. data instead of title in the column definitions.
Disclaimer
While I would recommend these changes in general just to improve your code, I would make sure to take a look at the format of the JSON that is being sent to and from the server. If you don't know how to do that I'd recommend downloading Fiddler to 'listen in' on the JSON data being sent.
If your JSON is wrong, no amount of changes to the page are going to make the table appear.
Finally, make sure you have no JS errors on the page. Use your browser's developer console (F12) to check that.
If you do find any JS errors, post them in your question. I'd also recommend posting the JSON data being sent to the question as well so that we can ensure the format is correct.
I am trying to learn how to use the Skyscanner Flights API with Google Script. It seems that the information available online is not adapted to newbies like me.
From what I got, the procedure to gain access to the flights' prices is :
- to send a HTTP POST request with information about which flights we want information about
- then send a HTTP GET request which will give us the pricing information
I would like to do that with Google Script.
Here is my code so far :
function sky1() {
/*
Link to Skyscanner.com help : http://business.skyscanner.net/portal/en- GB/Documentation/FlightsLivePricingList
Link to Skyscanner api demo (api key given there): http://business.skyscanner.net/portal/en- GB/Documentation/FlightsLivePricingQuickStart
*/
var apikey = "prtl6749387986743898559646983194";// is given on skyscanner website for testing
var url = "http://partners.api.skyscanner.net/apiservices/pricing/v1.0/?apikey=" + apikey;
// Post http request to skyscanner
var post_resp=sendHttpPost(url,apikey);
}
function sendHttpPost(url) {
// post_params
var post_params = {
"Country": "CH",
"Currency": "CHF",
"Locale": "en-GB",
"Adults": 1,
"Children": 0,
"Infants": 0,
"OriginPlace": "12015",
"DestinationPlace": "5772",
"OutboundDate": "2015-08-09",
"InboundDate": "2015-08-23",
"LocationSchema": "Default",
"CabinClass": "Economy",
"GroupPricing": true
};
var options =
{
"method" : "POST",
"contentType" : "application/json", // didn't get what this means
"payload" : JSON.stringify(post_params), // didn't get what this means
"muteHttpExceptions" : true, // avoids error message
};
var post_resp=UrlFetchApp.fetch(url,options);
Logger.log(post_resp.getResponseCode());
return post_resp;
}
Any help would be very appreciated. This gives me a 415 response rode instead of a 201 indicating that a session has been created.
PS: I am not a programmer, I would be very grateful if we keep thing simple.
Skyscanner API team here. You may be interested to see a reference Javascript implementation at https://github.com/Skyscanner/skyscanner-api-js. I also recommend using Fiddler (a network tracing tool) to compare the request/response from the test harness at http://business.skyscanner.net/portal/en-GB/Documentation/FlightsLivePricingQuickStart with that of your code.
I am trying to register a user in my Hybrid Worklight application. For this I am using an external REST API. The API says:
Request Method: POST
Request URL: https://${domainservice}/service/plan/${planName}/user?key=${key}&tenantId=${tenantId}
Request Headers: Content-Type:application/json
Request Payload:
{
"uid": "patricia",
"firstName": "Patricia",
"lastName": "Mayo",
"pic": "BASE64_ENCODED_IMAGE"
}
Field description:
uid (required): user's uid
firstName (optional): user's first name
lastName (optional): user's last name
pic (optional): user's picture encoded as base64 string
So I created a HTTP Worklight adapter:
function RegisterUser(userid) {
var input = {
method : 'post',
path : '/service/plan/App/user',
returnedContentType : 'plain',
headers: {'Content-Type' : 'application/json'},
parameters: {
'key':'e634bc60-0c6eba577258',
'tenantId': 'd93b921d-a56c-a645924fd548'
},
body : {
'contentType' : 'application/json',
'content' : JSON.stringify({
"uid" : userid})
}
};
return WL.Server.invokeHttp(input);
}
And I get this error:
{ "errors": [
],
"info": [
],
"isSuccessful": true,
"responseHeaders": {
"$wsep": "",
"Connection": "Keep-Alive",
"Content-Language": "en-US",
"Content-Type": "text\/html;charset=ISO-8859-1",
"Date": "Wed, 30 Jul 2014 14:47:27 GMT",
"Transfer-Encoding": "chunked",
"X-Backside-Transport": "FAIL FAIL",
"X-Client-IP": "199.127.32.67",
"X-Global-Transaction-ID": "48515650",
"X-Powered-By": "Servlet\/3.0"
},
"responseTime": 357,
"statusCode": 500,
"statusReason": "Internal Server Error",
I think is very weird that I set up
headers: {'Content-Type' : 'application/json'}
but in the response it looks like
"Content-Type": "text/html;charset=ISO-8859-1"
Also I want to point out some things I have already tried:
returnedContentType : 'plain' --> It is set to plain because if I set it to json I would get a JSON parse error
body content I also tried
var payload = "{\'uid\': \'"+userid+"\'}";
payload = payload.toString();
and then 'content' : payload
Using the RESTClient of the browser everything works fine
I tried using http port 80, http port 2080, and also https 443
I also tried writting the Host in the headers
I would not be too concerned about the format of the payload in the case where the server has hit an error condition - ideally servers would give us nicely formed error response but that's not always possible. Typically, if the expected response type in case of success is JSON then that's what I specify, and I just have to have enough error handling for cases when JSON parsing fails.
As to why you're getting the 500 error ... best I can suggest is to use a network monitor of some sort to discern the difference between the request issued via Worklight and the request as issued by the Browser's REST client.
You can set this up in Eclipse, Preferences->Run->TCP/IP Monitor ...
You may want to add a Host header. I've seen numerous times where it solved similar issues. E.g. if you're trying to connect to http://www.server.com/a/b/c/d add below header to your headers property
headers: {
Host: 'www.server.com'
}
I finally found the error. There is a defect in Worklight, the query parameters are removed and put into request body so the REST SERVICE does not receive key & tenantId. This is the final working code solution. Thank you anyways for your quick answers :)
function RegisterUser(userid) {
var payload = '{"uid": \"'+userid+'\"}';
var input = {
method : 'post',
path : '/service/plan/App/user?key=e630-db87-4803-bc45-57725c&tenantId=d9348af-a56c-a645924fd54e',
returnedContentType : 'application/json',
headers: {'Content-Type' : 'application/json'},
body : {
'contentType' : 'application/json',
'content' : payload.toString()
}
};
return WL.Server.invokeHttp(input);
}