I am trying to access the fluid survey API in Sales force. I use the following code but it responds with an error.
The code for controller class is:
public class fluidSurvey{
public String tst{set;get;}
public String result{get;set;}
public PageReference chk() {
//if (!ApexPages.hasMessages())
result=getData();
return null;
}
public String getData()
{
HttpRequest req= new HttpRequest();
Http http = new Http();
req.setMethod('GET');
String url = 'https://username:password#app.fluidsurveys.com/api/v2/surveys/';
req.setEndpoint(url);
HttpResponse res = http.send(req);
String json = res.getBody().replace('\n','');
tst = json;
try {
JSONObject j = new JSONObject( json );
return parseJson(j);
} catch (JSONObject.JSONException e) {
return 'Error parsing JSON response from Google: '+e;
}
}
public String parseJson(JSONObject resp){
String detail =resp.getString('total');
return detail;
}
}
and the code for apex page is:
<apex:page controller="fluidSurvey">
<!-- Begin Default Content REMOVE THIS -->
<h1>Fluid Survey</h1>
<apex:form >
<apex:outputText value="{!tst}"></apex:outputText>
<apex:commandButton value="Submit" action="{!chk}"/>
</apex:form>
</apex:page>
but when I click the submit button it create the following error:
System.CalloutException: For input string: "password#app.fluidsurveys.com"
Error is in expression '{!chk}' in component <apex:page> in page fluid-page
You need to explicitly set the Authorization header.
Try the following code:
public String getData()
{
HttpRequest req= new HttpRequest();
Http http = new Http();
req.setMethod('GET');
String authString = 'username:password';
String url = 'https://app.fluidsurveys.com/api/v2/surveys/';
req.setEndpoint(url);
req.setHeader('Authorization', 'BASIC ' + EncodingUtil.base64Encode(Blob.valueOf(authString)));
HttpResponse res = http.send(req);
String json = res.getBody().replace('\n','');
try {
JSONObject j = new JSONObject( json );
return parseJson(j);
} catch (JSONObject.JSONException e) {
return 'Error parsing JSON response from Google: '+e;
}
}
I don't believe you can use the username:password#host format to pass authenticate info in the URL for Callouts, you have to explicitly set an Authentication HTTP header in your request to pass the credentials instead. (exactly how you do this will depend on what authentication types the server supports)
Related
Here is the code for a helper function
public class SalesforceHelper {
public static void waitCall(String timeout){
System_Settings__c lnpSetting = System_Settings__c.getValues('System Properties');
String endpoint=lnpSetting.Base_Endpoint_URL__c + 'salesforceHelper/wait?timeout=' + timeout;
system.debug('====endpoint======'+endpoint);
HttpRequest httpReq=new HttpRequest();
HttpResponse httpResp = new HttpResponse();
Http http = new Http();
httpReq.setMethod('GET');
httpReq.setEndpoint(endpoint);
String username=lnpSetting.Endpoint_Username__c;
String password=lnpSetting.Endpoint_Password__c;
Blob headerValue = Blob.valueOf(username + ':' + password);
String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
httpReq.setHeader('Authorization', authorizationHeader);
httpReq.setHeader('content-type','application/json; charset=utf-8');
httpReq.setTimeout(120000);
try{
httpResp = http.send(httpReq);
System.debug('Wait response' + httpResp);
} catch (Exception e) {
system.debug(LoggingLevel.Error, 'Error HTTP response code = ' + httpResp.getStatusCode() + '; calling '+endpoint );
}
}
}
Basically this method just using HttpRequest and HttpResponse to call the endpoint URL, and the endpoint URL is web service, and it will just return 200 after the timeout that specified in the parameter.
Now the question is, I need to write a test case to cover this method, and I don't know how to write it.. I don't know how to mock the httpcallout properly, because this method doesn't return HttpResponse, and since the code is freeze right now, I cannot modified my class to make the test case work.
So any other way I can create the test class for this method?
You should definitely be able to use standard Http Callout Mock:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_testing_httpcalloutmock.htm
The only difference would be that you'd only set stats code:
// Create a fake response
HttpResponse res = new HttpResponse();
res.setStatusCode(200);
return res;
and check for response code:
System.assertEquals(200, res.getStatusCode());
From my rest client, i am hitting a web service and getting my response in the form of String {"code":"00000","msg":"Success"> . Now I am converting this in the form of JSONObject which i can then use further. But i am not able to. Below is the code i am using . Please guide.
private ResponseEntity<String> test()
{
final String uri = "URL";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);
System.out.println(result);
//This part is not working.
try {
JSONObject arr = new JSONObject((result));
for (int i = 0; i < arr.length(); i++) {
JSONObject abc = arr.getJSONObject(i);
System.out.println("test1 : " + abc.getString("test1"));
System.out.println("test2 : " + abc.getString("test2"));
System.out.println("test3 : " + abc.getString("test3"));
}
} catch (Exception e) {
}
return result;
}
Instead of converting to a generic JSONObject, you should create a class matching your response.
Spring will map the response to your model class using Jackson(behind the scenes). There is no need for converting it yourself.
So Let's say, you create a class
class Response {
String code;
String message:
//Gettes and Setters
}
Now you can change your code a bit like this
ResponseEntity<Response> result = restTemplate.exchange(uri, HttpMethod.GET, entity, Response.class);
Now if you useresult.getBody(), this would give your Response object, which you can use
One form is using JSONObject
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1</version>
<scope>${scope}</scope>
</dependency>
import org.json.simple.JSONObject;
JSONObject json = new JSONObject();
json.put("key1", value1);
json.put("key2", value2);
I tried to upload the file into Drop Box account From Salesforce Using /files_put Dropbox Api. But am always getting following Error :
[Status=Bad Request, StatusCode=400]{"error": "Body may not be empty"}.
Hereby My Code as follows,
public class DropboxController
{
public Blob FileBody{get;set;}
public DropboxController()
{
}
public PageReference DropAuth()
{
HttpRequest request = new HttpRequest();
request.setMethod('POST');
request.setTimeout(60000); request.setEndpoint('https://apicontent.dropbox.com/1/files_put/auto/Test.txt');
Blob val = csvFileBody;
Blob accesstoken = Blob.valueOf('<redacted>');
String AccToken = 'Bearer ' + EncodingUtil.base64Encode(accesstoken);
request.setHeader('Authorization', AccToken);
request.setBodyAsBlob(val);
System.debug(val);
Http hp = new Http();
HttpResponse response = hp.send(request);
System.debug(' RESP ::: ' +response +''+ response.getBody());
return null;
}
}
Please advise .
Thanks,
Vivek.K
I am not good with Web API. Here is my problem. I send an Json serialized object from my Windows Form Application. The object is an Entity table. When I do a get response it returns a 500 server error. Basically I plan to have multiple post methods in one controller which I may not be doing right. So I need you guys to guide me on what I have been doing wrong.
Here is my Controller:
[ResponseType(typeof(HttpWebResponse)), HttpPost, ActionName("MerchandiseApi")]
public HttpResponseMessage PostMain(IList<IMF_Main> mainFromConsolidator)
{
if (!ModelState.IsValid)
return Request.CreateResponse(HttpStatusCode.BadRequest, 2);
using (var anthill = new AnthillConsolidatorEntities())
{
var main = new IMF_Main();
foreach (var item in mainFromConsolidator)
{
main.BrandID = item.BrandID;
main.ItemID = item.ItemID;
main.CategoryID = item.CategoryID;
main.SubCategoryID = item.SubCategoryID;
main.ClassID = item.ClassID;
main.GenderID = item.GenderID;
main.CoaID = item.CoaID;
main.SubCoaID = item.SubCoaID;
main.First_SRP = item.First_SRP;
main.Current_SRP = item.Current_SRP;
main.Previous_SRP = item.Previous_SRP;
main.isSenior = item.isSenior;
main.isActive = item.isActive;
main.DateCreated = item.DateCreated;
anthill.IMF_Main.Add(main);
anthill.SaveChanges();
}
}
return Request.CreateResponse(HttpStatusCode.OK, 1);
}
Here's my WebApiConfig:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "MerchandiseApi",
routeTemplate: "api/{controller}/{action}"
);
}
Here is where the Uri gets built: I have 2 more tables to send but I will start with this. This goes to my first Post method to the server
var jsonMain = JsonConvert.SerializeObject(consolidatorEntities.IMF_Main, Formatting.None);
HttpPost("http://localhost:50826/api/Merchandise/PostMain", jsonMain) == 1.ToString()
public string HttpPost(string uri, string json)
{
string content = "";
try
{
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.Accept = "application/json";
request.ContentType = "application/json";
byte[] bodyBytes = Encoding.UTF8.GetBytes(json);
request.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length);
request.GetRequestStream().Close();
var response = (HttpWebResponse)request.GetResponse();
var sr = new StreamReader(response.GetResponseStream(), Encoding.GetEncod
ing("UTF-8"));
content = sr.ReadToEnd();
sr.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error sending data to Anthill \nException: " + ex, "Monytron - Consolidator", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return content;
}
Problem
The main problem is with your routing. Routes will check in order so when you post a request to http://localhost:50826/api/Merchandise/PostMain and you have these routes in order:
"api/{controller}/{id}"
"api/{controller}/{action}"
So the first route will match:
If your PostMain method is the only action with [HttpPost], then mainFromConsolidator will be null in your foreach loop you will receive a NullReferenceException that result in a 500 error.
If you have multiple method decorated with [HttpPost], then the call is ambiguous between those actions and you will receive an InvalidOperationExpception with "Multiple actions were found that match the request" message that result in a 500 error.
The other problem is you are using an ActionName("MerchandiseApi") but didn't post to that action.
Solution
You can use multiple solutions. As an option you can define only one route:
"api/{controller}/{action}/{id}"
This way you can create a controller that contains actions like these:
public class SomeController
{
// matches GET /api/some/action1
[HttpGet]
public HttpResponseMessage Action1()
// matches GET /api/some/action2/5
[HttpGet]
public HttpResponseMessage Action2(int id)
// matches POST /api/some/action3
[HttpPost]
public HttpResponseMessage Action3(SomeType someParameter)
// matches POST /api/some/action4
[HttpPost]
public HttpResponseMessage Action4(SomeType someParameter)
}
Anyway if you decide to define multiple routes, pay attention that routes will match in order and also if you used ActionName attribute, then use that name in url to call that action.
I am trying to generate a pdf and attach to an email and send it.
I am using salesforce and sendgrid.
I am able to send emails but the problem is when I try to attach the pdf, the email is with the attachment, but this is broken, the file is not empty, but the pdf says is broken (I think is a problem of conversion)
here is the code
Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
PageReference pdf = Page.include_attachment;
pdf.getParameters().put('id', 'xxxxxxxxxxxxxxxxxx');
blob fileBody = pdf.getContentAsPDF();
efa.setBody(fileBody);
efa.setFileName('test.pdf');
efa.setContentType('application/pdf;charset=UTF-8;');
send('xxxxx#xxxx.com','Test','Body Test', fileBody);
I tryied using
pdf.getContentAsPDF();
and
pdf.getContent();
but the result is the same.
Send method
public static void send(String emailRecipient, String emailSubject, String emailBody, Blob att){
Boolean success=true;
//construct the body of the request
String requestBody='';
requestBody += 'to='+EncodingUtil.urlEncode(emailRecipient,'UTF-8');
requestBody += '&from='+EncodingUtil.urlEncode(user.Email,'UTF-8');
requestBody += '&fromname='+EncodingUtil.urlEncode(user.Name,'UTF-8');
requestBody += '&subject='+EncodingUtil.urlEncode(emailSubject,'UTF-8');
requestBody += '&text='+EncodingUtil.urlEncode(emailBody.trim(),'UTF-8');
requestBody += '&html='+EncodingUtil.urlEncode(emailBody.trim(),'UTF-8');
requestBody += '&api_user=xxxxx';
requestBody += '&api_key=xxxxx';
requestBody += '&files[attachment.pdf]=#'+ EncodingUtil.base64Encode(att);
//construct request
HttpRequest req = new HttpRequest();
req.setEndpoint('https://sendgrid.com/api/mail.send.json');
req.setMethod('POST');
req.setBody(requestBody);
try{
//send request
Http h = new Http();
HttpResponse res = h.send(req);
//check response
String status = res.getStatus();
if(status.toUpperCase()=='OK'){
success=true;
}
else{
success=false;
}
}
catch(Exception e){
success=false;
}
}
Thank you
There is now a library/devtoolkit to do this for you. At the time of this writing it is in beta, but it is working. Disclaimer: I work at SendGrid and have just recently developed the library.
sendgrid-apex
You can rewrite your code to:
...
Blob att = pdf.getContentAsPDF();
public static void send(String emailRecipient, String emailSubject, String emailBody, Blob att){
SendGrid sendgrid = new SendGrid('username', 'password');
SendGrid.email email = new SendGrid.Email();
email.addTo(emailRecipient);
email.setFrom(user.Email);
email.setFromName(user.Name);
email.setSubject(emailSubject);
email.setText(emailBody.trim());
email.setHtml(emailBody.trim());
email.addAttachmentStream("attachment.pdf", att);
String response = sendgrid.send(email);
}