I'm attempting to write an APEX class that will add items to a global valueset, but in order to do so I need to know the ID of the global value set. Is there a way to find the ID of the global valueset (through APEX, not by looking at the URL) that a picklist field is using? Ideally I'd be able to do something similar to:
Case.picklistField__c.getdescribe();
and get a response that includes the ID of the global value set that it uses - that way I can then use my the metadataAPI to update the values.
Alternatively if I could find the global valueset by name I could use that with the metadata api as a work around.
UPDATE: Was able to get this to work using Eyescreams suggestion with the tooling API - full implementation:
String gvsName = 'TestValueSet'; //name of the global valueset you want the Id for goes here
HttpRequest req = new HttpRequest();
req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
req.setHeader('Content-Type', 'application/json');
req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm()+'/services/data/v41.0/tooling/query/?q=select+id+from+globalvalueset+Where+developername='+gvsName);
req.setMethod('GET');
Http httpreq = new Http();
HttpResponse res = httpreq.send(req);
system.debug(res.getBody());
SELECT Id, FullName, Description
FROM GlobalValueSet
But it's not available in straight Apex queries, you'd need Tooling API (meaning a REST callout). You can play with it in Developer Console -> Query Editor, just check the tooling api checkbox on bottom
These days you need to escape the variable like this:
String gvsName = 'TestValueSet'; //name of the global valueset you want the Id for goes here
HttpRequest req = new HttpRequest();
req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
req.setHeader('Content-Type', 'application/json');
req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm()+'/services/data/v48.0/tooling/query/?q=select+id+from+globalvalueset+Where+developername=\''+gvsName+'\'');
req.setMethod('GET');
Http httpreq = new Http();
HttpResponse res = httpreq.send(req);
system.debug(res.getBody());
Related
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.
I want to access the URL of the named credential and want to dynamically add some query parameters to it. Is it possible? Like in case of custom settings I access the value by get values directly. Does the named credential global variable credential provides me any such opportunity?
Refer to the documentation here:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_callouts_named_credentials.htm
This example is used:
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:***My_Named_Credential***/some_path');
As long as your named credential URL contains the protocol, subdomain (if required), hostname and port (id required) then you can append the path, parameters or fragments.
For example:
Map<String, String> urlParameters = new Map<String, String>{'client_id','12345'};
String urlParameterString = '';
for (String param : urlParameters.keySet()) {
urlParameterString += param+'='+urlParameters.get(param);
}
HttpRequest req = new HttpRequest();
req.setEndpoint(
String.format(
'callout:GoogleAPI/{0}?{1}#{2}',
new String[]{'oauth2', urlParameterString, 'anchorId'}
)
);
If the named credential URL was:
https://api.google.com
That endpoint should then be something like this:
https://api.google.com/oauth2?client_id=12345#anchorId
I am trying to call the Microsoft Graph API to create a domain. Unfortunately when I go to make the call, I receive an error stating that the "JSON Payload is empty".
Here is the call I am making:
GraphServiceClient _graphServiceClient =
new GraphServiceClient(new GraphAuthenticationHelper(NetOrgDomain));
HttpRequestMessage httpRequestMessage =
new HttpRequestMessage(httpMethod, requestUri);
string content = "{\"id\": \"sampleDomainAdd.info\"}";
var json = JsonConvert.SerializeObject(content);
var jsonContent = new StringContent(json, Encoding.UTF8, "application/json");
httpRequestMessage.Content = jsonContent;
HttpResponseMessage response =
await _graphServiceClient.HttpProvider.SendAsync(httpRequestMessage);
You've got an mix of Graph SDK and direct HTTP calls going on here. When using the Microsoft Graph .NET Client Library, you should be using the objects it provides rather than attempting to roll your own.
It also greatly simplifies your code:
var domain = await graphClient.Domains.Request().AddAsync(new Domain
{
Id = "sampleDomainAdd.info"
});
As an aside, the error you're getting currently is due to you're sending the data without the content-type being set to application/json in your HTTP request.
I am trying to authenticate via a service account from Salesforce.com to Google's DFP. I had the integration working under a previous user/credential pair, but am required to update to a new user.
I created the project/user/key pair in the Google Developer Console and added the new service account to the network in DFP. I then changed the "iss" value to be the new user's email and the private key to be the new private key from the keypair.
I am now receiving an 'Invalid Signature' error.
In SFDC, I am using Crypto.sign method with RSA-SHA256.
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_crypto.htm#apex_System_Crypto_sign
I have validated the key format to be PKCS#8 with header and new line characters removed per the documentation (I went so far as to decode the ASN.1 format and inspect the nodes for conformity).
Have I missed a step in the connection between the user and the correct credential? Is there a way for me to validate the signature that I am producing locally to see where I am going wrong? The only difference I have seen is that the old private key was shorter than the current private key.
Below is the code I am using to generate the JWT (again, this code functioned properly with a different username and credential key).
JWTHeader head = new JWTHeader();
head.alg = 'RS256';
head.typ = 'JWT';
JWTClaimSet claim = new JWTClaimSet();
claim.iss = '<username>#*.iam.gserviceaccount.com';
claim.scope = 'https://www.googleapis.com/auth/dfp';
claim.aud = 'https://accounts.google.com/o/oauth2/token';
claim.iat = DateTime.now().getTime() / 1000;
claim.exp = claim.iat + 3600;
System.debug(JSON.serialize(head));
System.debug(JSON.serialize(claim));
String key = '<privatekey>’;
String base = EncodingUtil.urlEncode(EncodingUtil.base64Encode(Blob.valueOf(JSON.serialize(head))), 'UTF-8') + '.' + EncodingUtil.urlEncode(EncodingUtil.base64Encode(Blob.valueOf(JSON.serialize(claim))), 'UTF-8');
String sig = EncodingUtil.urlEncode(EncodingUtil.base64Encode(Crypto.sign('RSA-SHA256', Blob.valueOf(base), EncodingUtil.base64Decode(key))), 'UTF-8');
String body = base + '.' + sig;
System.debug(body);
Http http = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint('https://accounts.google.com/o/oauth2/token');
req.setBody('grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=' + body);
req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
req.setMethod('POST');
HttpResponse resp = http.send(req);
Days later I found another solution that solved the issue. The problem was the base64urlsafe encoding. This encoding is not natively done in SFDC and perscribes the removal of trailing padding characters from the base64 string. Luckily, my original username encoded with no padding characters in the claim set. With the new username, the padding characters are present and must be removed before signing.
It all comes down to just a few characters.
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.