You need to sign in to do that
Don't have an account?
Hemanth Bakthavatsalu
Retrieve data from external system using HTTP calls
I am trying make a API call to an external system (CPQ) from the Salesforce.
1. I am able to successfully login to the external system through http post
2. After successful login, now I want to query Account object on the external system and retrieve the results
3. How do i make a query to the external system using Get method. When I make a external call after login, using a new request object with GET method, I am getting Unauthorized error.
Error that I am getting: System.HttpResponse[Status=Unauthorized, StatusCode=401]
The external system is CPQ (fpx vendor). Below is the API document that was shared
http://docs.fpx.com/docs/api/restful/14/html/cpq_login_(post).html
Below is the code:
public void cpqCallOut() {
HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
Http http = new Http();
String strname = 'Username';
String strpwd= 'password';
Blob headerValue = Blob.valueOf(strname+':'+strpwd);
String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
String SessionId = Userinfo.getSessionId();
String strURL = System.URL.getSalesforceBaseURL().toExternalForm();
req.setHeader('Authorization', authorizationHeader);
req.setEndpoint('https://sbx.fpx.com/rs/8/cpq/login');
req.setMethod('POST');
req.setBody('un ='+EncodingUtil.urlEncode(strname, 'UTF-8') + 'pw =' + EncodingUtil.urlEncode(strpwd, 'UTF-8') +
'SfdcSessionID =' + EncodingUtil.urlEncode(SessionId, 'UTF-8') +
'SfdcServerURL ='+ EncodingUtil.urlEncode(strURL , 'UTF-8'));
req.setCompressed(true); // otherwise we hit a limit of 32000
String strQuery = 'Select+name+from+Account+where+id+=+158000000000010';
//new request object
HttpRequest req1 = new HttpRequest();
HttpResponse res1 = new HttpResponse();
Http http1 = new Http();
try {
res = http.send(req);
if(res.getStatusCode()== 200)
{
System.debug('SUCCESS!!!');
req1.setMethod('GET');
req1.setEndpoint('https://sbx.fpx.com/rs/8/cpq?query='+ strQuery);
req1.setCompressed(true);
res = http.send(req1);
System.debug('MY REQUEST===>'+req1.toString());
System.debug('RESPONSE FROM CPQ 2222'+res.toString());
}
} catch(System.CalloutException e) {
System.debug('Callout error: '+ e);
System.debug('RESPONSE FROM CPQ'+res.toString());
}
}
}
1. I am able to successfully login to the external system through http post
2. After successful login, now I want to query Account object on the external system and retrieve the results
3. How do i make a query to the external system using Get method. When I make a external call after login, using a new request object with GET method, I am getting Unauthorized error.
Error that I am getting: System.HttpResponse[Status=Unauthorized, StatusCode=401]
The external system is CPQ (fpx vendor). Below is the API document that was shared
http://docs.fpx.com/docs/api/restful/14/html/cpq_login_(post).html
Below is the code:
public void cpqCallOut() {
HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
Http http = new Http();
String strname = 'Username';
String strpwd= 'password';
Blob headerValue = Blob.valueOf(strname+':'+strpwd);
String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
String SessionId = Userinfo.getSessionId();
String strURL = System.URL.getSalesforceBaseURL().toExternalForm();
req.setHeader('Authorization', authorizationHeader);
req.setEndpoint('https://sbx.fpx.com/rs/8/cpq/login');
req.setMethod('POST');
req.setBody('un ='+EncodingUtil.urlEncode(strname, 'UTF-8') + 'pw =' + EncodingUtil.urlEncode(strpwd, 'UTF-8') +
'SfdcSessionID =' + EncodingUtil.urlEncode(SessionId, 'UTF-8') +
'SfdcServerURL ='+ EncodingUtil.urlEncode(strURL , 'UTF-8'));
req.setCompressed(true); // otherwise we hit a limit of 32000
String strQuery = 'Select+name+from+Account+where+id+=+158000000000010';
//new request object
HttpRequest req1 = new HttpRequest();
HttpResponse res1 = new HttpResponse();
Http http1 = new Http();
try {
res = http.send(req);
if(res.getStatusCode()== 200)
{
System.debug('SUCCESS!!!');
req1.setMethod('GET');
req1.setEndpoint('https://sbx.fpx.com/rs/8/cpq?query='+ strQuery);
req1.setCompressed(true);
res = http.send(req1);
System.debug('MY REQUEST===>'+req1.toString());
System.debug('RESPONSE FROM CPQ 2222'+res.toString());
}
} catch(System.CalloutException e) {
System.debug('Callout error: '+ e);
System.debug('RESPONSE FROM CPQ'+res.toString());
}
}
}
req
, send it, and check the StatusCode that gets returned.Do you need to do something with the response to that initial POST request and feed it back into the subsequent GET request? Maybe read some sort of token response and use that to set a Header on the subsequent GET. Otherwise why are you doing the login call.
http://docs.fpx.com/docs/api/restful/14/html/cpq_login_(post).html
Based on that, I changed my code to make a POST using JSON format..
When I print the response object, I am getting the status code 200; however if I print the response body I am getting the below error. Does it indicate the login is not successful, eventhough I am getting status as 200.
USER_DEBUG [36]|DEBUG|RESPONSE BODY--->{"error":"Username or password is not recognized","success":false}
Updated code:
HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
Http http = new Http();
String strname = 'Username';
String strpwd= 'pwd';
String SessionId = Userinfo.getSessionId();
String strURL = System.URL.getSalesforceBaseURL().toExternalForm();
req.setEndpoint('https://sbx.fpx.com/rs/8/cpq/login');
req.setMethod('POST');
JSONGenerator gen = JSON.createGenerator(true);
gen.writeStartArray();
gen.writeStartObject();
gen.writeStringField('username', EncodingUtil.urlEncode(strname, 'UTF-8'));
gen.writeStringField('password', EncodingUtil.urlEncode(strpwd, 'UTF-8'));
gen.writeEndObject();
gen.writeEndArray();
String jsonOrders = gen.getAsString();
System.debug('jsonOrders: ' + jsonOrders);
req.setHeader('Content-Type', 'application/json');
req.setBody(jsonOrders);
req.setCompressed(true); // otherwise we hit a limit of 32000
try {
res = http.send(req);
if (res.getStatusCode() == 200) {
System.debug('CALLOUOT SUCCESSFUL');
System.debug('RESPONSE FROM CPQ 1111--->'+res.toString());
System.debug('RESPONSE BODY--->'+res.getBody());
}
}
catch(System.CalloutException e) {
System.debug('Callout error: '+ e);
System.debug('RESPONSE FROM CPQ'+res.toString());
}
Looking at the documentation you linked to, they have an option for a sfdcsessionid and sfdcserverurl. These might be better options that submitting your Salesforce user password. You can get the Session Id using UserInfo.getSessionId() (https://developer.salesforce.com/docs/atlas.en-us.198.0.apexcode.meta/apexcode/apex_methods_system_userinfo.htm#apex_System_UserInfo_getSessionId) in Apex.
I'd experiment with the API using something outside of Apex until you can get the raw JSON API calls going correctly. Then convert them to an Apex HttpRequest. I personally like the Postman plugin for Chrome.
I did a POST request and returned response body has User id and rfst id...
Response for login request:
{"rfst":"D9RnIQGcGOpa","userId":"09a0000evyj7m671","success":true}
Now I am trying to query the Account object through a GET request..I am getting the Unauthorized error when trying to do a Get request. I am following the step in “Query” function in the API document. (http://docs.fpx.com/docs/api/restful/14/)
HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
Http http = new Http();
req.setHeader('Connection','keep-alive');
req.setEndpoint('https://sbx.fpx.com/rs/8/cpq/login?un=Username&pw=Password');
req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
req.setMethod('POST');
req.setCompressed(true); // otherwise we hit a limit of 32000
//new request object
HttpRequest req1 = new HttpRequest();
HttpResponse res1 = new HttpResponse();
String strQuery = 'Select+name+from+Account';
try {
res = http.send(req);
if(res.getStatusCode()== 200)
{
System.debug('SUCCESS BODY!!!'+ res.getBody());
System.debug('RESPONSE FROM CPQ '+res.toString());
JSONParser parser = JSON.createParser(res.getBody());
String strUsrId;
while (parser.nextToken() != null) {
if(parser.getCurrentName() == 'rfst')
{
System.debug('getCurrentToken===>'+ parser.getCurrentToken());
System.debug('getCurrentName==>'+ parser.getCurrentName());
System.debug('getText===>'+ parser.getText());
strUsrId= parser.getText();
}
parser.nextToken();
}
System.debug('Userid===>'+ strUsrId);
req1.setMethod('GET');
req1.setHeader('Authorization', strUsrId);
req1.setHeader('Connection','keep-alive');
req1.setHeader('Content-Type', 'application/x-www-form-urlencoded');
req1.setEndpoint('https://sbx.fpx.com/rs/8/cpq?query='+ strQuery);
req1.setCompressed(true);
res1 = http.send(req1);
System.debug('GET REQUEST BODY===>'+req1);
System.debug('GET RESPONSE FROM CPQ 2222'+res1.toString());
}
POST: https://sbx.fpx.com/rs/8/cpq/login?un=username&pw=password
GET: https://sbx.fpx.com/rs/8/cpq?query=Select+name+from+Account
Whereas if i do the same thing in my code it is failing.. (the GET is failing; throwing below error)
System.HttpResponse[Status=Unauthorized, StatusCode=401
I believe the issue is with my GET request.
HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
Http http = new Http();
req.setHeader('Connection','keep-alive');
req.setEndpoint('https://sbx.fpx.com/rs/8/cpq/login?un=Username&pw=Password');
req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
req.setMethod('POST');
req.setCompressed(true); // otherwise we hit a limit of 32000
//new request object
HttpRequest req1 = new HttpRequest();
HttpResponse res1 = new HttpResponse();
String strQuery = 'Select+name+from+Account';
try {
res = http.send(req);
if(res.getStatusCode()== 200)
{
System.debug('SUCCESS BODY!!!'+ res.getBody());
System.debug('RESPONSE FROM CPQ '+res.toString());
JSONParser parser = JSON.createParser(res.getBody());
String strUsrId;
while (parser.nextToken() != null) {
if(parser.getCurrentName() == 'rfst')
{
System.debug('getCurrentToken===>'+ parser.getCurrentToken());
System.debug('getCurrentName==>'+ parser.getCurrentName());
System.debug('getText===>'+ parser.getText());
strUsrId= parser.getText();
}
parser.nextToken();
}
System.debug('Userid===>'+ strUsrId);
req1.setMethod('GET');
req1.setHeader('Authorization', strUsrId);
req1.setHeader('Connection','keep-alive');
req1.setHeader('Content-Type', 'application/x-www-form-urlencoded');
req1.setEndpoint('https://sbx.fpx.com/rs/8/cpq?query='+ strQuery);
req1.setCompressed(true);
res1 = http.send(req1);
System.debug('GET REQUEST BODY===>'+req1);
System.debug('GET RESPONSE FROM CPQ 2222'+res1.toString());
}
What Headers are you using with Postman? Do you use the userId from the prior login request as the Authorization header?
Do you need this line for the GET request - I think it is only applicable to a POST request.
1. POST: https://sbx.fpx.com/rs/8/cpq/login?un=USERNAME.cpqnew&pw=PASSWORD
Authorization: NO AUTH
Headers: NO HEADERS
Body:x-www-form-urlencoded
2. GET https://sbx.fpx.com/rs/8/cpq?query=Select+name+from+Account
Authorization: NO AUTH
Headers: NO HEADERS
BodyNO BODY
I am facing the same issue, although my use case is slightly different to yours. I am trying to connect to FPX CPQ On Demand through a web data connector that I am building, for pulling FPX Data into Tableau Desktop. I am writing a simple webpage using HTML and Javascript to make this webservice call to FPX. When I test my WebService calls with POSTMAN, I am able to connect. But I am struggling to figure out how to retain session when I make a GET Query call after establishing credentials through login call. Were you able to figure out this issue
Also, since you seem to be working on FPX CPQ ON Demand, I have a question. Do you know if CPQ's REST API supports OAUTH protocal for authentication?