scott.hurrey

Cross-Origin Resource Sharing; or Why I Can't Use AJAX with Learn APIs

Blog Post created by scott.hurrey on Nov 29, 2017

Recently several Blackboard folks participated in an event called HackPSU. HackPSU is an annual hackathon that takes place at Penn State University. During this awesome event, we discovered that some of the students were trying to use JQuery to make AJAX calls to the REST APIs, and they were failing. Upon further troubleshooting, we realized that the browser was rejecting the calls because of CORS. If you aren't familiar with CORS, there is a great write up on it by the Mozilla Developers Network.

 

Web-API-CORS.pngIn the heat of battle, we discovered the easiest way around it for development purposes is to simply disable web security in the Chrome browser. Sure, its easy, but even typing that makes me cringe. There are really only two options:

  • The REST API must support it; or
  • The client-side javascript must go through a proxy

 

Blackboard is looking at the best way to handle this on the API side, but at least in the short term, the only way to get around this is via a Proxy. A proxy, quite simply, accepts your applications API requests and forwards them to the appropriate endpoint. By doing so, the call doesn't come directly from the browser, and therefore does not require the OPTIONS request to be handled on the API side and therefore bypasses CORS altogether.

 

To illustrate this, I wrote a simple user account sign-up application in Angular 2, and used angular's built in proxy functionality to bypass CORS protection. Basically, the important bits all take place in three files.

  1. proxy.config.json
  2. package.json
  3. src/app/new-user-form/new-user-form.component.ts

 

proxy.config.json

 

In this file, we are, as you might imagine, configuring the proxy with JSON. There are tons of things you can do with this, but in our application, we are only implementing three. Here is the JSON file contents:

 

1{
2  "/learn/api/public/*": {
3   "target": "<Your Learn Domain>",
4   "secure": false,
5   "logLevel": "debug"
6  }
7}

 

In line 2, we are defining our search pattern. This tells Angular that this configuration should be applied any time an HTTP call is made to an endpoint that starts with /learn/api/public. Line 3 defines the domain to where the endpoint should be forwarded, so https://your.blackboard.com. Line 4 determines whether the endpoint should be secure. It is set to false in order to allow for testing against a development instance with a self-signed certificate. If you are moving your application to a production instance, this should be set to true. Lastly, on line 5, we are setting the logLevel for the proxy, to determine how much information is written to the console. Again, debug is great for development, but probably not so much for a production environment.

 

package.json

 

So now that we have configured the proxy, we have to tell angular that we want to implement it. This is done in the package.json file with a quick addition to the start script. To locate this script, open your package.json. You will see a "scripts" : { } tag and inside, you should see "start" : "ng serve". After ng serve and inside the double quotes, simply add a space and then --proxy-config proxy.config.json. That's all there is to it!

 

src/app/new-user-form/new-user-form.component.ts

 

So know you just have to call your endpoint. Contrary to many other examples, you don't call the endpoint directly. You call the endpoint in your proxy. So rather than calling GET https://your.blackboard.com/learn/api/public/v1/users, you simply call GET /learn/api/public/v1/users and the proxy takes care of the rest. Not only does this bypass CORS, but it makes it super simple to change the server you are calling without having to change each individual endpoint in your code.

 

So i hope this helps. As always, if you have any questions, feel free to ask here or email us at developers@blackboard.com.

 

Happy Coding!!

Outcomes