API Cookbook: Adding Course Content
Posted: 2013/05/17 Filed under: Uncategorized | Tags: API, cookbook, Valence Leave a comment »The API Cookbook is a new feature of the Valence Developer Blog. Each of the Cookbook posts will focus on an area of the Learning Framework or Mobile Module APIs. The posts will introduce the appropriate routes, JSON data and responses to fulfill a specific scenario.
The Valence Learning Framework APIs expose functionality to allow users to add and remove content from courses. The following examples show how these APIs could be used to create a standard outline for a course.
Suppose all courses must have the following modules:
- Introduction
- Marking Scheme
- Midterm Review
- Exam Review
If we have a list of courses identified by their Org Unit ID we can check to see if there is any content assigned and modify them as required.
We can consult the Valence documentation for routes that let us manipulate course content.
First we’ll retrieve the current content for a course with an Org Unit ID of 121535.
GET /d2l/api/le/1.0/121535/content/root/
200 OK
[
{
"Structure": [
],
"ModuleStartDate": null,
"ModuleEndDate": null,
"IsHidden": false,
"IsLocked": false,
"Id": 97657,
"Title": "Customs",
"ShortTitle": "",
"Type": 0
}
]
There appears to already be a module created for this course. Let’s delete it before we add our own modules.
DELETE /d2l/api/le/1.0/121535/content/modules/97657 200 OK
If we re-check the course content root we should receive an empty array.
GET /d2l/api/le/1.0/121535/content/root/ 200 OK []
Now we’re ready to add our own modules.
POST /d2l/api/le/1.0/121535/content/root/
{
"Structure": [
],
"ModuleStartDate": null,
"ModuleEndDate": null,
"IsHidden": false,
"IsLocked": false,
"Id": null,
"Title": "Marking Scheme",
"ShortTitle": "",
"Type": 0
}
200 OK
POST /d2l/api/le/1.0/121535/content/root/
{
"Structure": [
],
"ModuleStartDate": null,
"ModuleEndDate": null,
"IsHidden": false,
"IsLocked": false,
"Id": null,
"Title": "Introduction",
"ShortTitle": "",
"Type": 0
}
200 OK
POST /d2l/api/le/1.0/121535/content/root/
{
"Structure": [
],
"ModuleStartDate": null,
"ModuleEndDate": null,
"IsHidden": false,
"IsLocked": false,
"Id": null,
"Title": "Midterm Review",
"ShortTitle": "",
"Type": 0
}
200 OK
POST /d2l/api/le/1.0/121535/content/root/
{
"Structure": [
],
"ModuleStartDate": null,
"ModuleEndDate": null,
"IsHidden": false,
"IsLocked": false,
"Id": null,
"Title": "Exam Review",
"ShortTitle": "",
"Type": 0
}
200 OK
Now we can recheck the course content root and retrieve the module IDs. (If you’re making calls against a version 10.2.0 Learning Environment or later, the calls to create topics and modules should return to you information about each structure as you create them, so you’ll have the Module or Topic ID value at that point.)
GET /d2l/api/le/1.0/121535/content/root/
200 OK
[
{
"Structure": [
],
"ModuleStartDate": null,
"ModuleEndDate": null,
"IsHidden": false,
"IsLocked": false,
"Id": 97657,
"Title": "Introduction",
"ShortTitle": "",
"Type": 0
},
{
"Structure": [
],
"ModuleStartDate": null,
"ModuleEndDate": null,
"IsHidden": false,
"IsLocked": false,
"Id": 97658,
"Title": "Marking Scheme",
"ShortTitle": "",
"Type": 0
},
{
"Structure": [
],
"ModuleStartDate": null,
"ModuleEndDate": null,
"IsHidden": false,
"IsLocked": false,
"Id": 97659,
"Title": "Midterm Review",
"ShortTitle": "",
"Type": 0
},
{
"Structure": [
],
"ModuleStartDate": null,
"ModuleEndDate": null,
"IsHidden": false,
"IsLocked": false,
"Id": 97660,
"Title": "Exam Review",
"ShortTitle": "",
"Type": 0
}
]
Now the course has a standard set of modules created. Let’s set the start and end dates for the introduction module.
PUT /d2l/api/le/1.0/121535/content/modules/97657
{
"Structure": [
],
"ModuleStartDate": "2013-05-20T13:00:00.000Z",
"ModuleEndDate": "2013-05-24T22:00:00.000Z",
"IsHidden": false,
"IsLocked": false,
"Id": 97657,
"Title": "Introduction",
"ShortTitle": "",
"Type": 0
}
200 OK
As a final step let’s add a sub-module to the introduction.
PUT /d2l/api/le/1.0/121535/content/modules/97657/structure/
{
"Structure": [
],
"ModuleStartDate":null,
"ModuleEndDate": null,
"IsHidden": false,
"IsLocked": false,
"Id": null,
"Title": "Professor-Student Mixer",
"ShortTitle": "",
"Type": 0
}
200 OK
This covers the basics of manipulating modules in a course.
An introduction to Valence from Manitoba
Posted: 2013/05/02 Filed under: Uncategorized | Tags: community, Valence Leave a comment »The Valence Learning Framework APIs were recently given some time in the spotlight at the Manitoba Desire2Learn Regional User Forum. The presenter, Glenn Watt, was kind enough to share his slides. It’s great to see this type of knowledge-sharing within our developer community.
Troubleshooting your web applications using a network trace
Posted: 2013/03/26 Filed under: Uncategorized | Tags: software-development, trace Fiddler troubleshooting Leave a comment »The Challenge
Troubleshooting can be very time-consuming when there is a lot of back-and-forth to gather information on an issue. Human error can lead you to miss an important question, or to leave out details that might not seem relevant. Too often, these missed elements end up being the key to resolving an issue.
The Solution
A network trace provides clear, empirical information about an issue, and reduces the chance that important details will be left out. The trace provides visibility into the full body of the API calls, and shows any calls made before and after you encountered a problem. Having access to these contextual details can help pinpoint the root cause of an issue and lead to a quicker resolution.
The Details
A network tracing tool like Fiddler Web Debugger acts as a web proxy, capturing and presenting details about the traffic it is relaying. Examining a few examples of Fiddler’s functionality demonstrates the value of this type of tool for troubleshooting your code while you develop and deploy web applications. While each tool may take a slightly different approach, the general capabilities will be similar.
To start capturing traffic from your browser, simply launch Fiddler. Each action and response is logged in the Web Sessions pane on the left, and you can click on each item to view details of the transaction. To reduce the noise in the list of sessions, you can filter out success responses, and you can delete specific sessions that you deem irrelevant. For example, requests for CSS or images. Once the trace is cleaned up, you can save the report as a session archive that you can share with others while you work towards a solution.

A session captured in Fiddler shows a 502 error for a Remote Plugin widget that has failed to connect to the configured application.
If you need to debug an application that isn’t running locally, such as an application hosted on a server, you can allow Fiddler to receive traffic from a remote computer. Tools > Fiddler Options > Connections gives you the choice to allow Fiddler to receive traffic from a remote computer. You must restart Fiddler to activate this functionality.
In the following example, you can perform a trace of a PHP application that is designed to upload a file to a Learning Environment Dropbox. In order to receive traffic from the application, you need to modify the code to proxy traffic through your computer so that Fiddler can capture the details. The code snippet below shows an option that you can configure to proxy traffic to the computer where Fiddler is running; you should comment out this line when this proxy is no longer needed.
$ch = curl_init();
$options = array(
CURLOPT_PROXY => 'HOST_RUNNING_FIDDLER:8888',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CAINFO => getcwd().'/cacert.pem'
);
curl_setopt_array($ch, $options);
Once you start capturing traffic, you can see that the application is throwing a 500 error. In the pane on the upper right of the Fiddler interface, you can click the Inspectors tab and then click Headers to get details on the call being made. You see a well-formed POST, which includes the correct route and all of the appropriate keys and tokens for authentication. In the pane on the lower right, you can click WebView to display the full error message.

Viewing the details of a session captured in Fiddler shows the Headers in the upper right pane and the full error message in the lower right pane.
When you click TextView in the upper right pane, you can see the content being sent in the POST body. In this view, all looks well. But when you click View In Notepad, the issue becomes clear – the content is an unbroken line of text.
When you discover this unbroken string of text, you can inspect the code to discover that it uses LF for line endings instead of CR+LF. In PHP the CR is represented by “\r” while the LF is represented by “\n”. Without the CR, the message is not correctly formatted and the LMS fails to parse it. The history and implications of this convention are documented on Wikipedia.
$id = uniqid();
$data = "--".$id."\n".
"Content-Type: application/json\n".
"\n".
"{\"HTML\": null, \"Text\": \"Test\"}\n".
"--".$id."\n".
"Content-Disposition: form-data; name=\"\"; filename=\"file.txt\"\n".
"Content-Type: application/octet-stream\n".
"\n".
"--".$id."--";
A quick fix to this code results in an error-free Fiddler trace the next time you run the application.
The Result
This scenario is just one small example of how a trace can be of value in the troubleshooting process. And Fiddler is just one example of this type of tool. A quick web search or consulting a resource like StackOverflow will reveal myriad options that work on a variety of operating systems.
Adding a tool like Fiddler to your arsenal gives you good visibility into your web application’s behavior while debugging your own code, and allows you to share valuable and comprehensive information when working with others to troubleshoot an issue. For these reasons, it is important to include a trace when you contact Desire2Learn for development support. The data in a trace can go long way to helping us work with you to find a resolution to your issue.
Diving into Valence with the Course Search sample
Posted: 2013/03/08 Filed under: Uncategorized | Tags: remote-plugins, Sample, Valence Leave a comment »The Challenge
Getting your hands dirty with an API can be a daunting task. Where do you start? Experience is a great teacher, but how do you come up with a project that will provide a useful learning experience with real-world application?
The Solution
The Course Search sample provides you with a chance to explore a basic project, and opportunities to dive into the Valence Learning Framework APIs to get the widget running in your environment and extend the base functionality. This sample is a great first project for a developer who is new to the Valence platform. It is also a useful exercise for experienced developers who want to tackle an area of the Learning Framework API they might not have investigated before.
The Course Search sample is a remote plugin. As we saw with the Book Widget sample, remote plugins are easy to deploy. This widget is designed to compile a list of courses and allow users to filter the list by Semester and Department to find a specific course. You can try the online demo of this sample to get a feel for the basic functionality.
The Details
Before the widget can execute searches within your environment, you must complete some configuration. The necessary values are unlikely to change for an organization, so we make them constants for performance reasons. To perform the configuration, copy config.php.sample to config.php and change the values accordingly.
As with any application, the Course Search sample requires an App ID/Key pair and an appropriate User ID/Key pair in order to make calls against your LMS. To provide the application with the appropriate level of access, you must configure it to run under a service account with administrator privileges. By performing these configurations, you have an opportunity to work through the key request process and develop a stronger understanding of the authentication model.
- Follow the steps outlined in the App ID/Key pair topic to request a domain-limited key for the environment where you will be deploying the Course Search widget. Once approved, the key will be active in the environment within 24 hours.
- In config.php, set appId and appKey to the values for the key pair you receive.
- In the Getting Started Sample, update the appropriate fields to point to your LMS and use your App ID/Key pair.
- Click authenticate. You will be redirected to authenticate against your LMS. Enter credentials for the service account you configured to run this sample.
- When you are redirected back to the Getting Started Sample, note the User ID and User Key values.
- In config.php, set userId and userKey to the values returned by the authentication process.
For the variables outlined below, you’ll need to manually run some API calls to retrieve the appropriate values. As you did above, you can point the Getting Started Sample to your own LMS and then run the necessary API calls.
- Set rootOrg to the identifier property returned by GET /d2l/api/lp/1.0/organization/info (See organization info API documentation.)
- Set deptOrgType to the Id property returned by GET /d2l/api/lp/1.0/outypes/department (See department API documentation.)
- Set semesterOrgType to the Id property returned by GET /d2l/api/lp/1.0/outypes/semester (See semester API documentation.)
If you would like to run the Course Search widget for multiple LMSes, there is an opportunity to extend this sample by creating a more elaborate way to fetch and store these variables across multiple environments.
The Course Search widget uses the Organization Structure Learning Framework APIs to repeatedly walk down the organization structure to compile a list of courses. First, the widget performs a GET to retrieve the list of semesters. Then the widget performs a GET to retrieve a list of departments. You can see how this is done within the index.php file. These values are presented to the user as lists used to filter the courses.
Retrieving the list of courses is a three-stage process in the dept.php file. First, the widget performs a GET to retrieve the available course templates for the department that the user selected using the widget. Course templates are org units that link a course offering to a department. Course templates allow you to configure, store and reuse components of a course, such as quizzes, dropbox folders, and surveys, and then use the components in individual course offerings. For each template, the widget performs another GET to retrieve all of the courses that match the template. Finally, the widget performs a GET to retrieve all offerings for each course. These values are presented to the user in a drop-down list of available courses.
Once the user selects a specific course, the user interface displays a Submit button. This button provides an opportunity to extend the sample, as there is currently no functionality attached to it. Perhaps it could be used to copy the data to the clipboard so that the user can paste the information into the school’s enrollment system. There is a wide range of possibilities. Be sure to share your ideas for extending this sample in the comments.
The Sample
To use the Course Search widget in your own environment, you need to deploy it as a Remote Plugin.
- Download the current version of the Course Search sample. The sample requires PHP installed on the server where it is running.
- Log in to the Learning Environment as an administrator.
- Click on the Admin Tools icon and click Remote Plugins.
- Click on the New Remote Plugin button and fill out the Launch Point and Name. In this example, the Launch Point is the URL of the running instance of the Course Search sample.
- Change the Plugin Type dropdown to Widget.
- Add the Org Units that will have permission to run the Course Search widget by clicking the Add Org Units button.
- Click Save.
The Result
The Course Search sample is a development exercise that exposes you to key facets of the Valence platform – from application keys & authentication, to retrieving data, to deploying a remote plugin in the LMS. If you experimented with deploying and extending this sample, share your experience in the comments.
Remote plugins & the BookWidget sample
Posted: 2013/02/15 Filed under: Uncategorized | Tags: LTI, remote-plugins, Sample, Valence 6 Comments »The Challenge
A Desire2Learn Learning Environment administrator can install applications to offer greater functionality or streamline common processes for their users. However, there is some overhead involved in performing software updates to install these applications on the Learning Management System. Logically, reducing this installation overhead can reduce a barrier to adoption of an application.
The Solution
A remote plugin can extend the functionality of the LMS without requiring additional software. The remote plugin object has a rich content connection with the LMS, and provides UI elements that the developer can control. Using the BookWidget as an example, we will introduce some of the functionality that is possible through remote plugins and demonstrate the ease of building and deploying them.
The BookWidget is designed to allow an instructor to select textbooks to associate with their courses. Instructors can search by ISBN, title, or author to locate textbooks, and add or remove textbooks for each course they manage.
Students are presented with a user-friendly interface to determine which textbooks they need to acquire, including a thumbnail of the cover, and key information such as title and author. Where applicable, the BookWidget also provides students with a link to purchase textbooks from online retailers.
The Details
Remote plugin widgets are hosted separately from the LMS, which allows them to be enabled without performing software updates to the LMS. They take advantage of the Learning Tools Interoperability (LTI) specification to connect to the LMS. Once connected, the Valence Learning Framework APIs take over to provide interactivity with the LMS. The BookWidget sample is a VisualStudio 2010 project, which is available to download from our public code repository.
A remote plugin widget loads within an iframe embedded in a course homepage. When a student or instructor loads a page that contains a remote plugin widget, the widget issues an LTI launch request, which results in a POST to the URL configured as the target for the remote plugin widget. The POST contains a set of fields described in the LTI documentation. Once the widget extracts these fields from the POST data, it generates the application context to create the appropriate LTI authorization parameters. The LTI authentication takes place using OAuth, which uses a shared key and secret between the remote plugin and the widget code. The widget then redirects to the generated authentication URL. After authentication is completed, the widget reloads at its launch URL.
Once the LTI launch is complete, the remote plugin widget uses the Learning Framework APIs to perform actions against the LMS. For the BookWidget, this includes retrieving and manipulating information related to the books assigned to a particular course. The BookWidget uses an HTTP POST to the appropriate route to associate a book with a course. It uses an HTTP DELETE to remove a book from a course. And it uses an HTTP GET to retrieve the list of associated books for a course. When we developed the BookWidget, we identified the Learning Framework APIs we needed and then tested them interactively to ensure they behaved as we expected. We performed this interactive testing using the Getting Started Sample. Then we built those routes into the BookWidget application.
Because a remote plugin is hosted separately from the LMS, it does not inherit the look and feel of the course homepage. It is not yet possible to retrieve LMS CSS information using the APIs, so the BookWidget uses a simple design with minimal embellishments to allow it to blend in with the LMS styles. The sample was built using Bootstrap to help make styling easier.
The Sample
Setting up the BookWidget in your own environment demonstrates how easy it is to deploy a remote plugin.
- Download the current version of the BookWidget sample. The sample requires Visual Studio 2010.
- Log in to the Learning Environment as an administrator.
- Click on the Admin Tools icon and click Remote Plugins.
- Click on the New Remote Plugin button and fill out the Launch Point and Name. In this example, the Launch Point is the URL of the running instance of the BookWidget. If running the sample from Visual Studio it will likely be “http://localhost:6371/books“.
- Change the Plugin Type dropdown to Widget.
- Add the Org Units that will have permission to run the BookWidget by clicking the Add Org Units button.
- Click Save.
Once the BookWidget is configured, an instructor can add it to their course homepage and start using it.
The Result
As we’ve demonstrated, a remote plugin provides LMS users with additional functionality without the overhead of software updates. The BookWidget sample demonstrates how a remote plugin can use LTI and the Learning Framework APIs to offer a rich user experience.
Try the BookWidget sample in your own environment. Share your experience implementing and extending this sample in the comments. If you create your own remote plugins, be sure to let us know. We’d love to feature your work in a future blog post!
Slides from Valence API Presentations
Posted: 2012/07/18 Filed under: Uncategorized Leave a comment »Those of you at Desire2Learn Fusion (Desire2Learn’s annual users groupe) that wanted slides from the Valence API presentations I have attached them. to this post
If you are not at fusion, I will set up a little context for you. Extensibility Success Stories is a review of various projects that have been completed or in progress to illustrate the varied uses of the extensibility. The intention of the presentation is to trigger ideas about how developers can create novel experiences or streamline workflows for Desire2Learn users. The theme of the year was ”Chart your Course” and was nautical; so this presentation extends that metaphore and is around “touring cool sites”. The presentation is available as Extensibility Success Stories
The metaphor for the second presentation is to provide you with a “Map of Valence”. This presentation covers resources and processes you need to get started and then digs into some of the “here be dragons” areas and general tool direction. This overview is another form of guide to getting started and is available as Map of Valence
There were a number of other interesting presentations targeted to developers or people interested in extensions for Desire2Learn.







