6

I've spent some time this week playing with Canvas. I've setup an example that uses OAuth to authenticate and authorise the app; it then retrieves a record, and makes an update to the record from the app. This is done with the REST API.

Initially, I checked the links property of the context, but it only lists the standard REST API endpoints. I then started to look for ways of calling custom web services. For ease, I started with a custom REST web service; it was not possible to call this even when using a c.instance.visual.force.com address, as that redirects to the standard instance.visual.force.com, and there's a access-control-allow-origin policy issue.

I thought for a moment about using events - creating an event in the app that's picked up in the page, which can then call logic in a controller. However, Canvas events seem to be geared at allowing cross-app communication, rather than app-to-host communication.

Am I missing something, or is Canvas currently just aimed at providing an easier entry point to the standard API options?

EDIT: Thanks to Andy for his quick response! He's correct in that you can craft a URL to point to the instance URL rather than a relative URL that's on the force.com domain. This would work from a server making a callout, and it does answer the original question; however, I'd be interested in other answers around making this work from within the app page (i.e. Javascript). Currently, the code in the accepted answer won't work as it does not allow calls to instance.salesforce.com from c.instance.visual.force.com.

  • What language are you developing your app in? – Andrew Fawcett Oct 18 '13 at 12:15
  • Currently this is just a proof of concept/me playing around with Canvas, so it's actually just Javascript in a HTML page hosted on Dropbox (I know Javascript better than I do server side solutions). Is that any help? – GBreavin Oct 18 '13 at 12:21
  • Yeah gives me something to focus on, your using the Salesforce Canvas Javascript SDK then I assume? – Andrew Fawcett Oct 18 '13 at 12:25
  • Yes, that's correct. I've used the example in the Canvas documentation as a starting point, and added to it. Out of interest - if it was a server side language, would you have had an answer? – GBreavin Oct 18 '13 at 12:36
  • Actually just asking, as I have a Java Canvas app I could repurpose to help illustrate an answer. Regardless, of server or client, the info you need is in the CanvasRequest structure, your correct the Links section only gives known Salesforce API's, my solution would be to use the InstanceURL in the Client structure to dynamically form the end point you need for SOAP, i was going to check if the REST URL they give can just be appended with the URL mapping defined in your Apex class. – Andrew Fawcett Oct 18 '13 at 13:08
4

In order to make Apex REST calls from your Chatter page via JavaScript you need to utilise the client proxy built into canvas. There is some more detail and examples of this here.

var sr = JSON.parse('<%=signedRequestJson%>');
// Reference the Chatter user's URL from Context.Links object.
var url = sr.context.links.chatterFeedsUrl+"/news/"+sr.context.user.userId+"/feed-items";
var body = {body : {messageSegments : [{type: "Text", text: "Some Chatter Post"}]}};

Sfdc.canvas.client.ajax(url,
    {client : sr.client,
        method: 'POST',
        contentType: "application/json",
        data: JSON.stringify(body),
        success : function(data) {
        if (201 === data.status) {
             alert("Success");
             }
        }
    });

To call an Apex REST service you will need a URL that looks like this...

https://eu1.salesforce.com/services/apexrest/myresource

Where 'myresource' is defined via @RestResource(urlMapping='myresource') in Apex

I've looked at the CanvasRequest (via in my case the Eclipse Java Debugger) and see this.

enter image description here

So in order to construct the correct URL to an Apex REST service and utilise the approach above via the proxy you would need to do something like this...

   var url = sr.client.instanceUrl + "/services/apexrest/myresource";

I would say that I've not had time to test the above, but from my reading of the docs above, my understanding of the CanvasRequest and the samples this should hopefully get you going!

  • Thanks Andy! I can see this working in a server side scenario, however, I don't think it would be possible from within the app's page (i.e. via Javascript) - I'm pretty sure it doesn't work, I had an error, and decided on another approach rather than fight it! Still marking your answer as accepted as it does answer the question at the top, but I'll edit the question as well. Thanks again! – GBreavin Oct 18 '13 at 15:00
  • No worries, glad it was some use, just to clarify though the above is a JavaScript example (I just used a preview of the CanvasRequest contents from a Java app). If I get some time over the weekend, I might have a go at this and will come back to this answer for future readers. Thanks in the meantime and good luck with your alternative solution! – Andrew Fawcett Oct 18 '13 at 15:25
  • Doh! Of course it's Javascript :) My eye picked up the <%=signedRequestJson%> which associates with server solutions. Unfortunately, I've tried something similar to your solution, and it doesn't work - there's a "Origin is not allowed by Access-Control-Allow-Origin" error. You're right - the doc links make it sound like this should be possible, but my experience is telling me otherwise! DM me on twitter if you do decide to play with it at the weekend, I'll share my file with you. – GBreavin Oct 18 '13 at 15:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.