LTI Resource Search Developers Guide

LTI Resource Search Developers Guide

1EdTech Final Release
Version 1.0
1EdTech Final Release
Date Issued:6 May 2019
Status:This document is made available for adoption by the public community at large.
This version: https://www.imsglobal.org/spec/lti-rs/v1p0/devguide/

IPR and Distribution Notices

Recipients of this document are requested to submit, with their comments, notification of any relevant patent claims or other intellectual property rights of which they may be aware that might be infringed by any implementation of the specification set forth in this document, and to provide supporting documentation.

1EdTech takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on 1EdTech's procedures with respect to rights in 1EdTech specifications can be found at the 1EdTech Intellectual Property Rights web page: http://www.imsglobal.org/ipr/imsipr_policyFinal.pdf.

Copyright © 2019 1EdTech Consortium. All Rights Reserved.

Use of this specification to develop products or services is governed by the license with 1EdTech found on the 1EdTech website: http://www.imsglobal.org/speclicense.html.

Permission is granted to all parties to use excerpts from this document as needed in producing requests for proposals.

The limited permissions granted above are perpetual and will not be revoked by 1EdTech or its successors or assigns.

THIS SPECIFICATION IS BEING OFFERED WITHOUT ANY WARRANTY WHATSOEVER, AND IN PARTICULAR, ANY WARRANTY OF NONINFRINGEMENT IS EXPRESSLY DISCLAIMED. ANY USE OF THIS SPECIFICATION SHALL BE MADE ENTIRELY AT THE IMPLEMENTER'S OWN RISK, AND NEITHER THE CONSORTIUM, NOR ANY OF ITS MEMBERS OR SUBMITTERS, SHALL HAVE ANY LIABILITY WHATSOEVER TO ANY IMPLEMENTER OR THIRD PARTY FOR ANY DAMAGES OF ANY NATURE WHATSOEVER, DIRECTLY OR INDIRECTLY, ARISING FROM THE USE OF THIS SPECIFICATION.

Public contributions, comments and questions can be posted here: http://www.imsglobal.org/forums/ims-glc-public-forums-and-resources.

© 2019 1EdTech Consortium, Inc. All Rights Reserved.

Trademark information: http://www.imsglobal.org/copyright.html

  1. Abstract

The Learning Tools Interoperability (LTI) Resource Search specification defines how to search digital repositories for a set of resources via a web services API. The standard addresses searching learning object repositories (LORs), and other catalogs of learning resources. The specification supports executing these search from learning tools using various attributes of resources and returning full metadata about the resources to the learning tools. Results can be launched either as URLs or LTI links. The goal of the LTI Resource Search standard is a standard way for students and teachers to be able to search resource providers, such as learning object repositories, from single sources or aggregated from multiple sources, within a learning object consumer such as a learning management system or other educational platform.

  2. Introduction

This section is non-normative.

  2.1 Scope and Context

The purpose of this document is to provide an easy to use guide for developers, particular LTI Resource Search Consumers, to get started developing with the standard.

  3. Getting Started: A Developer's Guide

This section is non-normative.

  3.1 Am I a consumer or a provider?

As a consumer, you will be constructing calls to a REST API to search digital resource repositories. These calls will conform to the LTI Resource Search specification.

  • As a consumer, you will be constructing calls to a REST API to search digital resource repositories. These calls will conform to the LTI Resource Search specification.
  • As a provider, you will be exposing your digital resource repository through a REST API conforming to the LTI Resource Search specification.

This guide primarily focuses on the consumer role, coaching you through authorization steps as well as the construction of basic queries.

  3.2 Authorization

LTI Resource Search endpoints are not required to be secured (that’s up to the person exposing the data) but oftentimes the endpoints will be. The LTI Resource Search specification dictates that when these endpoints are secured, they should be secured behind tokens provided by authorization systems using the OAuth 2.0 specification. OAuth 2.0 token endpoints can use various OAuth 2 grant types to produce a token, but for this example we’ll take a look at how to retrieve a token for a common OAuth 2.0 grant type, ‘client_credentials’.

  3.2.1 Retrieving a Token

To retrieve a token, you’ll be making a POST to the OAuth 2.0 token endpoint. To successfully get back a token, you will need the following pieces of information:

  • Username - You will need a valid username for which to retrieve a token. This will be given to you by the endpoint administrator
  • Client id - The client id is a unique id that identifies you, the caller, to the authentication system. This id is given to you by the endpoint administrator.
  • Client secret - The client secret is a secret string that is known to both you, the caller, and the authorization endpoint. Again, this will be given to you by the endpoint administrator. Do not share your client secret with anyone else.

Once you’ve gathered those three pieces of information, you’ll need to prepare the client id and secret for inclusion on the request. The client id and secret are not included in plain-text on the POST. Instead, the client id and secret need to be appended together, Base64-encoded, and then included as a header value.

First, combine your client id and secret, separated by a colon (:)

my_id:my_secret

Next, use a Base64 encoder to create an encoded version of that string. Your language of choice will have a Base64 encoder available or you can find one using a quick Google search. For this demo, I’ve used https://www.base64encode.org/. Running that string though a Base64 encoder, I get:

bXlfaWQ6bXlfc2VjcmV0

Now it’s time to make the request to the token endpoint to acquire a token. For the request, you’ll need to include two headers, and some JSON in the request body.

Example call:

POST https://imsglobal.org/ims/rs/v1p0/token

Example authorization header:

  • Header key: Authorization
  • Header value: Basic BASE64_ENCODED_STRING_GOES_HERE

Replace BASE64_ENCODED_STRING_GOES_HERE with the Base64 encoded version of your client and secret. For the example above, the value for the Authorization header would be “Basic bXlfaWQ6bXlfc2VjcmV0”

  • Header key: Content-Type
  • Header value: application/json

You need to tell the token endpoint that you’ll be passing JSON in the POST body

Example body:

In the body of the request, you need to tell the token endpoint what grant_type you’ll be using and which user id you’re attempting to retrieve a token for. In this case, you are using ‘client_credentials’ for the grant type. This is the grant type that uses client ids and secrets. For the username, replace user@schoolco.com with the username given to you by the authorization endpoint administrator.

{"grant_type":"client_credentials","username":"user@schoolco.com"}

Now that you’ve constructed your headers and included the grant type and username in the POST body, POSTing to the token endpoint will get you a token for accessing the resource search endpoints.

Example access token response from token endpoint:

        {
            "access_token": "3fb1738c61bb13ef4cfb5943cc18255c7cea41b9d7d3be59297f2fdd5a0f6b15",
            "expires_in": 2592000
        }
      

  3.3 The basics

Once you’ve successfully acquired an access token for the LTI Resource Search endpoints (if necessary), you’re ready to begin searching the resource repository. There are two REST API methods that are exposed as part of the LTI Resource Search specification; an endpoint for exposing the list of subjects contained within the resource repository, and an endpoint that allows for searching the resource repository. Before we can use those methods, we’ll need to get an access token in order to securely request data from those LTI Resource Search endpoints.

  3.4 Subjects

Because a resource repository can contain resources for either a very specific or a broad number of subjects, each repository fronted by an LTI Resource Search-conforming REST API provides an endpoint listing the subjects included in the repository:

  3.4.1 For consumers:

If you are building queries that search by subject, you will want to limit your searches to subjects returned by the subjects endpoint. Searches for subjects not included in that list will likely result in no results. If you are not running subject-based searches then there is no reason for you to call this API.

  3.4.2 For providers:

This is your indicator to consumers which subjects they can search that will yield actual results. There is no requirement on your end for this data to be 100% timely so you can choose a method of returning this data that best fits your needs. Some options:

  • Return a hard-coded list of supported subjects (simple)
  • Query the list from for your repository and then cache it for a period of time (a little more costly)
  • Query the list every time (most accurate, but the highest cost).

  3.4.3 Fetching Subjects

To retrieve the subjects supported by a particular resource repository, you will make a GET call to the /subjects endpoint. If the endpoint has been secured using OAuth 2.0, you’ll need to include the retrieved auth token as a header parameter in the request.

Example call:

GET https://imsglobal.org/ims/rs/v1p0/subjects

Example authorization header (if necessary):

  • Header key: Authorization
  • Header value: Bearer AUTH_TOKEN_GOES_HERE

Replace AUTH_TOKEN_GOES_HERE with the actual auth token received from the OAuth 2.0 token endpoint.

Example result:

        {
          "subjects": [
            {
              "identifier": 1,
              "name": "Mathematics",
              "parent": "0"
            },
            {
              "identifier": 2,
              "name": "Geometry",
              "parent": "1"
            },
            {
              "identifier": 4,
              "name": "Algebra",
              "parent": "1"
            }
          ]
        }
      

The result that comes back is a JSON array of subject objects. Each subject contains an identifier that uniquely identifies the subject in the resource repository, the name of the subject, and the identifier of this subject’s parent. Subjects can be hierarchical so it is up to you to (if desired) turn the flat subject array into the correct hierarchy based on the parent identifier relationships. In the result above, there is one top-level subject (Mathematics) and two child subjects (Geometry and Algebra) whose parent is Mathematics.

  3.5 Searching Resources

The core endpoint of the LTI Resource Search specification is /resources. This endpoint allows a user to find resources within the exposed repository that match specific criteria. The endpoint supports simple a simple query language, sorting, and pagination.

To fetch resources from a resource repository, make a GET against the /resources endpoint. If the endpoint has been secured using OAuth 2.0, you’ll need to include the retrieved auth token as a header parameter in the request.

Example call:

GET https://imsglobal.org/ims/rs/v1p0/resources

Example authorization header (if necessary):

  • Header key: Authorization
  • Header value: Bearer AUTH_TOKEN_GOES_HERE

Replace AUTH_TOKEN_GOES_HERE with the actual auth token received from the OAuth 2.0 token endpoint.

The resulting JSON returned from the /resources endpoint will be an array of Resource objects that match the filters passed in as query parameters. Because no parameters were passed in, the default behavior of the /resources endpoint it to return the first 100 results. A sample result-set looks like this:

          "resources": [
            {
              "id": 1,
              "name": "RESOURCE_001",
              "description": "This is a searchable resource - 001",
              "publisher": "Education Co.",
              "subject": [
                    "Mathematics"
              ],
              "url": "https://www.educationco.com/resources/1",
              … more attributes are here...
            },
            {
              "id": 2,
              "name": "RESOURCE_002",
              "description": "Another searchable resource - 002",
              "publisher": "Education Co.",
              "subject": [
                    "Geometry"
              ],
              "url": "https://www.educationco.com/resources/2",
              … more attributes are here...
            }
          ]
        }
      

In this case, the resource search returned two results. For this example, I’ve removed most of the attributes to save space. For a complete list of what can be returned for a resource, see the Resource Payload section of the LTI Resource Search REST/JSON bindings: https://www.imsglobal.org/sites/default/files/spec/lti-rs/v1p0/rest_binding/rsservicev1p0_restbindv1p0.html#TabUMLJSONMap_CoreClass_Resource

  3.5.2 Filtering Resources

To concentrate the list of resources returned by the /resources endpoint to something more specific, you’ll use the filter query parameter. Filters allow you to specify a data field, a predicate, and a value in order to refine the result-set returned by the /resources endpoint to a specific set of resources that match your criteria.

As an example, lets search for resources that are in one of the subjects listed above. To find all the resources with a subject of ‘Geometry’:

  • Data field - This is the field containing the resource’s subject value. In our case, the data field would be ‘subject’.
  • Predicate - We want resources that exactly match the subject name that we’re searching for so we use an equal sign ‘=’. The equals predicate does an exact match on the data field value.
  • Value - The value to match on. In this case, we want resources with a subject value of ‘geometry’. All comparisons are case-insensitive so we can pass ‘geometry’ or ‘Geometry’ or ‘GeOmEtRy’ and get the same results. Because this is a string value, it needs to be enclosed in single quotes.

Putting them together, our filter becomes:

subject=’geometry’

To add this as a filter in the query string, the filter will need to be URL encoded. The URL encoding process makes strings safe for being included as query parameters on a URL string. URL encoding the above filter turns it into:

subject%3D%27geometry%27

For more information on URL encoding, see the following page: https://www.w3schools.com/tags/ref_urlencode.asp

To search the resource repository using the URL encoded filter, add it as the value for the filter query parameter at the end of the /resources endpoint.

Example call:

GET https://imsglobal.org/ims/rs/v1p0/resources?filter=subject%3D%27geometry%27

Example authorization header (if necessary):

  • Header key: Authorization
  • Header value: Bearer AUTH_TOKEN_GOES_HERE

Replace AUTH_TOKEN_GOES_HERE with the actual auth token received from the OAuth 2.0 token endpoint.

The above call will search the resource repository and return only resources marked as being in the Geometry subject.

For more details on which data fields can be searched and which predicates are supported, see the Searching for Resources section of the LTI Resource Search REST/JSON bindings: https://www.imsglobal.org/sites/default/files/spec/lti-rs/v1p0/rest_binding/rsservicev1p0_restbindv1p0.html#Main3p1

  3.5.3 Complex Filtering

Searches within the resource repository do not have to be limited to a single filter. Two filters can be chained together in order to refine the list of returned resources even further. Building on the example above, let’s say that the user not only wants to view resources in the Geometry subject, but that user particularly cares about resources having to do with triangles. Like before, we need to construct a filter using a data field, predicate, and value.

For this case, let’s use the ‘description’ data field. This is the field containing a detailed description of the contents of the resource. Since we don’t know the exact description of the resources we want, we really just want to find resources with ‘triangle’ in the description. To do this, you’ll use the ‘~’ operator. The tilde ‘~’ operator matches on resources that contain the value string anywhere within the data field. To find all resources with ‘triangle’ somewhere in the description, the filter would be:

description~’triangle’

Now that we have two filters, they’ll need to be combined into a single filter string. Filter strings can be combined using AND or OR. Using AND will only return resources that match both conditions. Using OR will return resources that match either of the conditions. For this case, we’ll use AND.

subject=’geometry’ AND description~’triangle’

Like before, this will need to be URL encoded:

subject%3D%27geometry%27%20AND%20description~%27triangle%27

Now that the combined filter has been constructed, make the call just like before.

Example call:

GET https://imsglobal.org/ims/rs/v1p0/resources?filter=subject%3D%27geometry%27%20AND%20description~%27triangle%27

Example authorization header (if necessary):

  • Header key: Authorization
  • Header value: Bearer AUTH_TOKEN_GOES_HERE

Replace AUTH_TOKEN_GOES_HERE with the actual auth token received from the OAuth 2.0 token endpoint.

The above call will now search the resource repository and return only resources marked as being in the Geometry subject that contain ‘triangle’ in their description.

  3.5.4 Errors

At some point in your filter construction, it is likely that you will make a mistake and construct an invalid query. Using the above case as an example, let’s say you forgot to wrap your filter value in single quotes.

subject=geometry

Which, when URL encoded would be:

subject%3Dgeometry

In the case when the resource search endpoint cannot parse your query due to poor construction, an error payload will be returned instead of an array of resources. If your filter happens to result in zero matches, the return payload will look like this:

        {
          "resources": []
        }
        
        If an error occurred, the payload will look like this:
        {
          "CodeMajor": "failure",
          "Severity": "error",
          "CodeMinor": "invalid_data",
          "Description": "Wrong filter parameter"
        }
      

It is very important to be able to distinguish between an empty result set and an error payload. The error payload’s ‘Description’ field will do its best to explain to you what went wrong. It’s also possible that your auth token was incorrect, in the wrong place, or expired. In the case of your query being rejected due to lack of authorization, the return payload will look like this:

        {
          "error": "Unauthorized"
        }
      

If you receive an ‘Unauthorized’ error, make sure that you included the auth token and that you included it in the right place. The most common authorization error is forgetting that your auth token needs to be preceded by the text “Bearer “.

  3.5.5 Sorting, Paging, and Field Selection

If you find yourself dealing with very large result sets, you may find yourself in need of the sorting, paging, or field selection functionality provided by the /resources endpoint. In the case above, it’s possible that the resource repository has hundreds of resources in the Geometry subject with ‘triangle’ in the description.

Tip: The exact number of resources that meet the filter criteria can be found by looking at the X-Total-Count header value on the response from the /resources endpoint.

To better find the specific resources that you’re looking for, result sets can be sorted by any of the available data fields. To sort the returned resources, you will use the following query parameters:

For the original subject search, to sort the results by name in ascending (A-Z) order, the query would look like this:

&sort=name&orderBy=asc

https://imsglobal.org/ims/rs/v1p0/resources?filter=subject%3D%27geometry%27&sort=name&orderBy=asc

If the number of returned results is overly large, you can request a specific page of data using the limit and offset query parameters.

  • limit - The number of total records to return. Specifying a limit of 10 will only return 10 resources.
  • offset - The index of the resource result to start with. If you consider your result set as an array, offset controls which array index your results will begin at. If an offset of 55 is specified, the /resources endpoint will only return the resources at index 55 and above. Offset is 0-based meaning that there is an item at index 0, an item at index 1, etc. so specifying an offset of 4 will cause your result set not to contain resources at indexes 0, 1, 2, and 3.

By combining limits and offsets, you can view small subsets of your data, letting you (if building a user interface) give your user the option of paging through the data in small chunks.

To view the first 10 records in the above result set (indexes 0 through 9 of the result array), your query would look like this:

&limit=10&offset=0

https://imsglobal.org/ims/rs/v1p0/resources?filter=subject%3D%27geometry%27&sort=name&orderBy=asc&limit=10&offset=0

The next page of data (indexes 10 through 19) could be fetched by increasing the offset to the index of the first record in the next page.

&limit=10&offset=10

https://imsglobal.org/ims/rs/v1p0/resources?filter=subject%3D%27geometry%27&sort=name&orderBy=asc&limit=10&offset=10

Tip: As a helper, the /resources endpoint will automatically generate paging URLs for you and include them in the response header under the “Link” key.

Last, if you only care about very specific resource fields, you can control which data fields are returned for each resource using the fields query parameter:

  • fields - A comma-separated list of the fields you want returned for each resource

If you want to limit the data coming back from the /resources endpoint to just the name and subject of each resource, your fields parameter would look like this:

&fields=name,subject

Combining the above queries, you can get the names and subjects of page 4 (indexes 30-39) of the Geometry resources sorted by name:

https://imsglobal.org/ims/rs/v1p0/resources?filter=subject%3D%27geometry%27&sort=name&orderBy=asc&limit=10&offset=30&fields=name,subject

  A. Revision History

This section is non-normative.

  A.1 Version History

Version No.Release DateComments
1EdTech Final Release [LTI-RS-10] 10th September 2018 First release of this specification.

  B. References

  B.1 Informative references

[LTI-RS-10]
LTI Resource Search 1.0. 1EdTech Consortium. URL: https://www.imsglobal.org/lti-rs/v1p0/

  C. List of Contributors

The following individuals contributed to the development of this document:

Name Organization Role
Jill Hobson1EdTech Consortium (USA)Editor
Adam BlumACT (USA)Task Force Co-chair
Vikash JaiswalACT (USA)Task Force Co-chair
Paul DeVePearson Education (USA)Task Force Co-chair
Colin Smythe1EdTech Consortium (USA)Editor

1EdTech Consortium, Inc. ("1EdTech") is publishing the information contained in this document ("Specification") for purposes of scientific, experimental, and scholarly collaboration only.

1EdTech makes no warranty or representation regarding the accuracy or completeness of the Specification.

This material is provided on an "As Is" and "As Available" basis.

The Specification is at all times subject to change and revision without notice.

It is your sole responsibility to evaluate the usefulness, accuracy, and completeness of the Specification as it relates to you.

1EdTech would appreciate receiving your comments and suggestions.

Please contact 1EdTech through our website at http://www.imsglobal.org.

Please refer to Document Name: LTI Resource Search Developers Guide 1.0

Date: 6 May 2019