Trying to insert Contact, getting 400 Bad Request - google-mirror-api

I'm attempting to insert a Contact to the Mirror API, but I keep getting a 400 Bad Request error.
My code to build the request is as follows:
Http h = new Http();
HttpRequest firstPost = new HttpRequest();
firstPost.setEndpoint('https://www.googleapis.com/mirror/v1/contacts');
firstPost.setMethod('POST');
firstPost.setHeader('Authorization', 'Bearer ' +access_token);
System.debug('Bearer '+access_token);
firstPost.setBody(postBody);
firstPost.setHeader('Content-Type', 'application/json');
The postBody is hardcoded for now as:
{
"kind":"mirror#contact",
"id":"harold",
"displayName":"Harold Penguin",
"imageUrls": ["https://developers.google.com/glass/images/harold.jpg"]
}
I've confirmed the access_token is being sent. Any ideas? Thanks!

You don't need (and should not specify) the kind attribute when doing contact.insert. This is assumed (you better be inserting a contact), and I can see how it might be causing problems if you provide it. Notice that https://developers.google.com/glass/v1/reference/contacts/insert does not list it as an attribute, and the Raw HTTP example does not show it.

Related

dropbox-api get_thumbnail_v2 & get_thumbnail returns question marks(?) inside rhombs ()

I am trying to use DropBox API to get a thumbnail from DropBox and show them on Lightning Web Component in Salesforce, but can not do it because in a response Apex receiving body with black rhombs and question marks inside.
I use standard HTTP method to call
HttpRequest req = new HttpRequest();
req.setHeader('Authorization', 'Bearer sl.validToken');
req.setHeader('Dropbox-API-Arg', '{"resource": {".tag": "path","path": "/folderName/pictureName.jpg"},"format": "jpeg","size": "w64h64","mode": "strict"}');
req.setHeader('Content-Type', 'text/plain; charset=utf-8');
req.setEndpoint('https://content.dropboxapi.com/2/files/get_thumbnail_v2');
req.setMethod('POST');
Http httpreq = new Http();
HttpResponse res = httpreq.send(req);
this is what I receive in body of response in Apex. The same response I have in Postman.
https://i.stack.imgur.com/90yjI.png
This is what I have in DropBox explorer with same values and headers (JSON)
https://i.stack.imgur.com/ytDxv.png
File scope is Read to everyone. SF Remote Site Settings & CSP Trusted Sites are set.
Short update:
I`ve been able to get JSON From header. I did use that piece of code:
List<String> headers = new List<String>(res.getHeaderKeys());
for(String key : headers){
System.debug('key ->>> '+key+' = '+res.getHeader(key));
}
String jsonString = res.getHeader('Dropbox-Api-Result');
System.debug('->>>ddd '+jsonString);
But still do not understand how to use it as a thumbnail in LWC.
Thank you in advance for your help.
The /2/files/get_thumbnail_v2 Dropbox API endpoint is a "content-download" style endpoint, meaning the "response body contains file content, so the result will appear as JSON in the Dropbox-API-Result response header". So, the illegible value you're receiving is the actual bytes of the thumbnail data itself. You're currently attempting to display it as text, but you'll instead need to save and display it as an image to see the thumbnail. Refer to your platform's documentation for information on how to display an image.
For reference, the Dropbox API v2 Explorer is built with knowledge of the different endpoint formats, so in this case it displays the metadata from the Dropbox-API-Result response header, and just offers the file data, in this case the thumbnail data, as a download via a "Download" button.

How to send Twilio SMS via Web Service in Salesforce Apex

I want to send SMS from Twilio noticed they have libraries built for Java, .Net, Node, etc. so that we can use them if we are upto those technologies.
But I want to do the same from Salesforce Apex and trying to figure out how to build the Http parameters to make the authorization.
I tried to map with cURL example given in Twilio documentation and can't find header keys for Auth token.
Below is my current code and looking for how to set the authentication params.
req.setEndpoint(baseURL + '/2010-04-01/Accounts/account_sid/Messages.json');
req.setMethod('POST');
req.setHeader('to', EncodingUtil.urlEncode('+to_number', 'UTF-8'));
req.setHeader('from', EncodingUtil.urlEncode('+from_number', 'UTF-8'));
Http ht = new Http();
HttpResponse res = ht.send(req);
Updated request :
Blob headerValue = Blob.valueOf('my-twilio-account-sid:my-twilio-auth-token');
String authorizationHeader = 'BASIC ' + EncodingUtil.base64Encode(headerValue);
req.setHeader('Authorization', authorizationHeader);
req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
String body = EncodingUtil.urlEncode('From=+from_number&To=+to_number&Body=Sample text from twilio', 'UTF-8');
req.setBody(body);
Http ht = new Http();
HttpResponse res = ht.send(req);
Response saying
Bad Request : A 'From' phone number is required.
The phone numbers don't go in the headers.
For the headers you will need
Content-Type: "application/x-www-form-urlencoded"
then you will need another header for authorization
Authorization: auth-string
where auth-string is a combination of the string Basic followed by a space followed by a base64 encoding of twilio-account-sid:twilio-auth-token (replace with your Twilio credentials joined by the colon) so the header will look something like
Authorization: "Basic ABCiDEdmFGHmIJKjLMN2OPQwR2S3TUVzABliCDE3FGc1HIo2JKL2MjNwOPcxQRSwTUc1Vzc0XmYhZAB3CDElFGH1Jw=="
The body of the POST request should contain key, value pairs of To, From and Body, something like
"From=" + twilio-phone-number + "&To=" + to-number + "&Body=" + message-body (replace with string values for phone numbers and message).
I hope this helps.

POST multipart/form-data with NodeRed HTTP request

I'm trying to generate a HTTP Webrequest in NodeRed that will upload a file to a website via a normal upload form. I guess i knwo how to upload a file, but i do not know how to pass the other input fieds i have to fill also.
I only found how to set http headers:
msg.headers["content-type"] = "multipart/form-data";
This is what i have so far:
I have also tried in "the missing part" to write the FormData and send the Request manually. (https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects)
But also no luck with that. Only received an Error that FormData is unknown...
In the function node, before sending msg, set request header like this
msg.headers = {
"content-type":"application/x-www-form-urlencoded"
}

Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter..?

I am trying to send a PUT request to an amazonS3 presigned URL. My request seems to be called twice even if I only have one PUT request. The first request returns 200 OK, the second one returns 400 Bad Request.
Here is my code:
var req = {
method: 'PUT',
url: presignedUrl,
headers: {
'Content-Type': 'text/csv'
},
data: <some file in base64 format>
};
$http(req).success(function(result) {
console.log('SUCCESS!');
}).error(function(error) {
console.log('FAILED!', error);
});
The 400 Bad Request error in more detail:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidArgument</Code>
<Message>Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter, Signature query string parameter or the Authorization header should be specified</Message>
<ArgumentName>Authorization</ArgumentName>
<ArgumentValue>Bearer someToken</ArgumentValue>
<RequestId>someRequestId</RequestId>
<HostId>someHostId</HostId>
</Error>
What I don't understand is, why is it returning 400? and What's the workaround?
Your client is probably sending an initial request that uses an Authorization header, which is being responded with a 302. The response includes a Location header which has a Signature parameter. The problem is that the headers from the initial request are being copied into the subsequent redirect request, such that it contains both Authorization and Signature. If you remove the Authorization from the subsequent request you should be good.
This happened to me, but in a Java / HttpClient environment. I can provide details of the solution in Java, but unfortunately not for AngularJS.
For the Googlers, if you're sending a signed (signature v4) S3 request via Cloudfront and "Restrict Bucket Access" is set to "Yes" in your Cloudfront Origin settings, Cloudfront will add the Authorization header to your request and you'll get this error. Since you've already signed your request, though, you should be able to turn this setting off and not sacrifice any security.
I know this may be too late to answer, but like #mlohbihler said, the cause of this error for me was the Authorization header being sent by the http interceptor I had setup in Angular.
Essentially, I had not properly filtered out the AWS S3 domain so as to avoid it automatically getting the JWT authorization header.
Also, the 400 "invalid argument" may surface as a result of wrong config/credentials for your S3::Presigner that is presigning the url to begin with. Once you get past the 400, you may encounter a 501 "not implemented" response like I did. Was able to solve it by specifying a Content-Length header (specified here as a required header). Hopefully that helps #arjuncc, it solved my postman issue when testing s3 image uploads with a presigned url.
The message says that ONLY ONE authentication allowed. It could be that You are sending one in URL as auth parameters, another - in headers as Authorization header.
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:scavenger_inc_flutter/utils/AuthUtils.dart';
import 'package:scavenger_inc_flutter/utils/URLS.dart';
class ApiClient {
static Dio dio;
static Dio getClient() {
if (dio == null) {
dio = new Dio();
dio.httpClientAdapter = new CustomHttpAdapter();
}
return dio;
}
}
class CustomHttpAdapter extends HttpClientAdapter {
DefaultHttpClientAdapter _adapter = DefaultHttpClientAdapter();
#override
void close({bool force = false}) {
_adapter.close(force: force);
}
#override
Future<ResponseBody> fetch(RequestOptions options,
Stream<List<int>> requestStream, Future<dynamic> cancelFuture) async {
String url = options.uri.toString();
if (url.contains(URLS.IP_ADDRESS) && await AuthUtils.isLoggedIn()) {
options.followRedirects = false;
options.headers.addAll({"Authorization": await AuthUtils.getJwtToken()});
}
final response = await _adapter.fetch(options, requestStream, cancelFuture);
if (response.statusCode == 302 || response.statusCode == 307) {
String redirect = (response.headers["location"][0]);
if(!redirect.contains(URLS.IP_ADDRESS)) {
options.path = redirect;
options.headers.clear();
}
return await fetch(options, requestStream, cancelFuture);
}
return response;
}
}
I disallowed following redirects.
Used the response object to check if it was redirected.
If it was 302, or 307, (HTTP Redirect Codes), I resent the request after clearing the Auth Headers.
I used an additioal check to send the headers only if the path contained my specific domain URL (or IP Address in this example).
All of the above, using a CustomHttpAdapter in Dio. Can also be used for images, by changing the ResponseType to bytes.
Let me know if this helps you!
I was using django restframework. I applied Token authentication in REST API. I use to pass token in request header (used ModHeader extension of Browser which automatically put Token in Authorization of request header) of django API till here every thing was fine.
But while making a click on Images/Files (which now shows the s3 URL). The Authorization automatically get passed. Thus the issue.
Link look similar to this.
https://.s3.amazonaws.com/media//small_image.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXXXXXXXXXXXXXXXXXXXX%2F20210317%2Fap-south-XXXXXXXXFaws4_request&X-Amz-Date=XXXXXXXXXXXXXXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
I lock the ModHeader extension to pass Authorization Token only while making rest to REST API and not while making resquest to S3 resources. i.e. do not pass any other Authorization while making request to S3 resource.
It's a silly mistake. But in case it helps.
Flutter: if you experience this with the http dart package, then upgrade to Flutter v2.10!
Related bugs in dart issue tracker:
https://github.com/dart-lang/sdk/issues/47246
https://github.com/dart-lang/sdk/issues/45410
--> these has been fixed in dart 2.16, which has been shipped with Flutter v2.10!
https://medium.com/dartlang/dart-2-16-improved-tooling-and-platform-handling-dd87abd6bad1

POST Request unable to receive the JSON respose in Salesforce

I am calling an API of FluidSurvey. when i make a POST request ... it post the request on the fluidSurvey but i didnt get the JSON response. rather it returns nothing. any suggestion??
my controller code
public class fluidSurvey{
public String tst{set;get;}
public String result{get;set;}
public PageReference chk() {
getData();
return null;
}
public void getData(){
String apiKey = 'xxxxxx';
String pwd = 'xxxxxx';
String u = 'https://app.fluidsurveys.com/api/v2/surveys/survey_id/responses/';
HttpRequest req = new HttpRequest();
Http http = new Http();
HTTPResponse res;
try{
req.setEndPoint(u);
req.setTimeout(2000);
req.setMethod('POST');
Blob headerValue = Blob.valueOf(apikey + ':' + pwd);
String authorizationHeader = 'Basic '+ EncodingUtil.base64Encode(headerValue);
req.setHeader('Authorization', authorizationHeader);
req.setHeader('Content-Type', 'application/json');
req.setHeader('Content-Length','31999');
res = http.send(req);
tst= res.toString();
catch(Exception e){
System.debug('Callout error: '+ e);
System.debug(tst+'--------'+res);
}
}
}
and the Apex page code is
<apex:page controller="fluidSurvey">
<apex:form >
<apex:pageBlock title="New Fluid Surveys API">
<apex:outputText value="{!tst}"></apex:outputText><br/>
<apex:pageBlockButtons location="bottom">
<apex:commandButton value="Submit" action="{!chk}"/>
</apex:pageBlockButtons>
</apex:pageBlock>
</apex:form>
and api documentation link is http://docs.fluidsurveys.com/api/surveys.html#getting-a-list-of-surveys..
FluidSurveys Dev here.
Looks like you're doing a POST request, which according to the docs is for creating a new response. But your function is named getData, so I'm assuming you want to get a list of responses?
Change the request type from GET to POST and it should start to work.
Also, the response type will be application/json, but you shouldn't be setting the request type to that encoding.
If I'm mistaken and you're looking to submit a new response, then this code wouldnt work because you're not actually passing any content.
As you can see by http://docs.fluidsurveys.com/api/surveys.html#submitting-a-new-response you need to actually pass a dictionary of question ids and answers. The best way to figure out what the ids are or what the format is, is to first look at the response returned from a GET request.
The problem with my code was that i setting a content-length header, but not setting any body,the server is diligently waiting for the 3199 byte body. so after using the setBody method my code properly returns a json response
I wanted to add to this answer in that I found that some messages from Apex being posted to external endpoints were getting dropped by firewalls on the other end due to intrusion detection rules.
Apparently, there are conditions where on the Apex end, outbound messages do not conform to certain construction rules that prevent man-in-the-middle attacks and some firewalls or IDS are blocking them. This will appear on the Apex side as a "Read Time Out".
The specific IDS rule is CVE-2009-3555 (http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3555).
If you are experiencing read timeouts in Apex to external endpoints and can't isolate them to apex programming, you might do some logging on the destination firewall to see if this is the issue, and if it is, create an exception in that firewall for this type of case.

Resources