Overview

A powerful Cloud LMS is one that is able to integrate with other enterprise applications, such as ERPs, HR softwares, reporting tools etc. Interconnection between such systems is key to streamline organizational processes and improve business performance.

What can you do with APIs

OData

OData (Open Data Protocol) is an OASIS standard that defines a set of best practices for building and consuming RESTful APIs. OData helps you focus on your business logic while building RESTful APIs without having to worry about the various approaches to define request and response headers, status codes, HTTP methods, URL conventions, media types, payload formats, query options, etc. OData also provides guidance for tracking changes, defining functions/actions for reusable procedures, and sending asynchronous/batch requests. OData RESTful APIs are easy to consume. The OData metadata, a machine-readable description of the data model of the APIs, enables the creation of powerful generic client proxies and tools. Details about OData protocol http://www.odata.org

Limitations

The maximum page size is 10,000 items. When a result set spans multiple pages, API returns an @odata.nextLink property in the response that contains a URL to the next page of results.

Multiregions

LMS365 is resided in multiple datacenter to provide the best performance to the customers. Depends on region customer selected for his tenant he can access to particular LMS365 API end point which correspond to selected region to get the best performance.

RegionAPI End Point
Central UShttps://us-api.365.systems
North Europehttps://ne-api.365.systems
Japan Easthttps://je-api.365.systems
Australia Easthttps://au-api.365.systems
Canada Centralhttps://ca-api.365.systems
United Kingdom Southhttps://uk-api.365.systems
Germany West Centralhttps://de-api.365.systems
Switzerland Northhttps://ch-api.365.systems
U.S. Government GCChttps://va-api.usgcc365.systems

Also we preserved compatibility with previous end point https://api.365.systems (https://api.usgcc365.systems for US Government GCC) so right now the end point works like a reverse proxy which resolves customer region from Authorization header and route api request to the needed region based API end point.

Get Tenant Region

To get best performance from LMS365 API you can use direct region based API end point. To get the end point which related to your tenant send GET request to the following end point:

where <tenantUrl> is your SharePoint url, for example https://yourtenantname.sharepoint.com

The response will have the following format:

    {
    "apiUrl": "https://je-api.365.systems/",
    "assetsUrl": "https://je-assets.365.systems/",
    "appInfos": { /* LMS365 SharePoint Add-ins info */ }
    }

After getting this information you can cache/save it depends on application you do.

Authenticate via API Key

To get an Api Key please contact your LMS365 Administrator. After you get API key you can use it for Basic authentication to LMS365 API end points. This way of authentication is useful when you want to access to all tenants data.

Authenticate via Bearer Authorization header

This way intended to use from SharePoint Online pages on the same tenant where app is installed, via JavaScript. The way provides ability to request API under current logged-in user(in SharePoint Online).

Note: This example is based on SharePoint Add-in authentication which is obsolete now. For modern SharePoint sites and pages we recommend to use SPFx authentication. You can find the sample code that demonstrates how to use it here https://github.com/elearningforce/lms365.spfx-samples

Example of usage:

  1. Go to SharePoint page where you want put JavaScript that use LMS365 API. Edit page and insert embed code.

  2. Then you need to put code that acquires user LMS365 API token and your application code that use the token.

    <script src="https://assets.365.systems/assets/js/lms" type="text/javascript"></script>
    <script type="text/javascript">
        (function () {
            var appTypes = {Scorm: 1, CourseCatalog: 2, Assignments: 3, LearningPath: 4, Quiz: 5}
            var lms = window['ef.lms365'];
            //we pass appTypes.CourseCatalog because we have CourseCatalog installed on the site where we paste the code.
            //if you have another app installed please pass it instead of appTypes.CourseCatalog
            lms.QueryExecuterProvider.instance.get(appTypes.CourseCatalog) 
                .then(function (queryExecutor) {
                    queryExecutor.execute({ url: '/odata/v2/Courses' })
                        .then(x => {
                            //process courses here
                        });
                });
        })();
    </script>

As example consider the code that gets all courses and then gets enrollments of the first course using LMS365 API:

    <script src="https://assets.365.systems/assets/js/lms" type="text/javascript"></script>
    <div id="lms365courses"><img src="/_layouts/15/images/loading.gif"/></div>    
    <script type="text/javascript">
        (function () {
            var appTypes = {Scorm: 1, CourseCatalog: 2, Assignments: 3, LearningPath: 4, Quiz: 5}
            var lms = window['ef.lms365'];

            lms.QueryExecuterProvider.instance.get(appTypes.CourseCatalog)
                .then(function (queryExecutor) {
                    queryExecutor.execute({ url: '/odata/v2/Courses' })
                        .then(x => {
                            var element = document.getElementById("lms365courses");                            
                            element.innerHTML = "Courses count: " + x.value.length;                          
                            
                            // get enrollments for the first course
                            queryExecutor.execute({ url: '/odata/v2/Courses?$expand=Enrollments&$filter=Id eq ' + x.value[0].Id })
                                .then(x => {
                                    element.innerHTML += '<br/> First course enrollment count:' + x.value[0].Enrollments.length                                    
                                });
                        });
                });
        })();
    </script>

Request to API will be performed under current logged-in user account and some API endpoints will return current user specific data and not all, like in case of API key authentication. That's the key difference between these two approaches.

Code sample: Enroll current user to course

   <script src="https://assets.365.systems/assets/js/lms" type="text/javascript"></script>
   
   <script type="text/javascript">
       (function () {
           var appTypes = {Scorm: 1, CourseCatalog: 2, Assignments: 3, LearningPath: 4, Quiz: 5}
           var httpMethods = {GET:0, POST:1}
           var targetCourseId = 'D5CF2DB7-86E4-479C-8D96-29870D09F30D'

           var lms = window['ef.lms365'];
           lms.QueryExecuterProvider.instance.get(appTypes.CourseCatalog)
               .then(function (queryExecutor) {
                   queryExecutor.execute({ url: '/odata/v2/Courses('+targetCourseId')/Enroll', method: httpMethods.POST })
                       .then(x => {
                           alert('Enrolled')
                       })
                       .catch(e => {
                           console.log(e)
                       });
               });

       })();
   </script>

Handle Tenant Region Has been Changed Error

Some customers who already had provisioned tenant in some region may require change it and move their data closer to end users. In this case if your client code cashed tenant region you need consider invalidate logic. Consider situation: Customer has provisioned tenant in NorthEurope. Some developer on his side developed JS application which use LMS365 API with the following code:

    var xhr = new XMLHttpRequest();
    xhr.addEventListener("readystatechange", function () {
        if (this.readyState === 4) {
            //process LMS365 courses
        }
    });

    xhr.open("GET", "https://ne-api.365.systems/odata/v2/Courses");
    xhr.setRequestHeader("authorization", "Bearer <access token>");
    xhr.setRequestHeader("cache-control", "no-cache");

    xhr.send(null);

The developer knows that tenant resided in North Europe but one day customer has decided to move tenant to the US region. He contact our support team and we move tenant to Central US region. After that code above will get 409(Conflict) response error with new URIs. It means that request goes to the NorthEurope but tenant is resided in Central US region. Response will have JSON format and contains information about new region based API end point:

{
  "errorCode": "TenantRegionHasBeenChanged",
  "environmentConfigData": {
    "apiUrl": "https://us-api.365.systems:443/",
    "assetsUrl": "https://us-assets.365.systems/",
    "appInfos": { /* LMS365 SharePoint Add-ins info */} 
  }
}

environmentConfigData object contains information about new region API end point.