This is a detailed design document on the Course Blocks API and how it enables xBlocks on Mobile.

 


Goal

To provide a REST interface for accessing course structure and course blocks for a user.

Background

The edX MOOC platform provides an online learning experience for students via scheduled and self-paced courses.  Educators create courses by either using edX's Studio (a GUI-based course-authoring tool) and/or directly manipulating XML files in edX's published OLX format.  Learners interface with the platform using an LMS (Learning Management System).  The LMS is also used by educators to administer and track live versions of courses.

Course

An edX Course encapsulates the various components that make up a learner's experience in a run of a course (session).  For example, it includes a discussion forum for students and educators to interact, course announcements to update students, a handouts corner for reference information, and other tabular components as customized by the course author.  In the context of this document, these are all peripheral components of a course and not considered further.  Instead, we focus on the courseware, which provides a structural learning pathway, and henceforth simply referred to as the course.

A Course structure is a hierarchical Recursive Composition of primitive and composite objects known as xBlocks. The course structure is a mutable directed acyclic graph (why?) with nodes representing navigational/structural elements (such as sections and subsections), dynamic user-targeted course pathways (such as split test modules), and pedagogical primitives (such as instructional content/videos and student assessments). The course structure is designed to be flexible to support an arbitrary depth of navigation elements and an arbitrary breadth of pathways.

Each edit of the course is uniquely versioned whenever a course author modifies the course structure or any of its components.  A production-level course would typically have anywhere from about 150 to 3000 xBlocks.  A typical MOOC-sized student enrollment could be anywhere from 1,000 to 100,000 students.

xBlock

An xBlock is the basic building block of any edX course.  It controls its own data structure (model), its own HTML rendering (view), and its own business logic (controller).  An xBlock executes in a runtime, which provides common services/utilities, user/request context, and storage.  While the course structure data is primarily stored in a database infrastucture called modulestore, an xBlock's persistence is configured on a field-by-field basis by designating the scope for each of its fields.  Some scopes support user-specific data, which results in different xBlock content for different target users.

An xBlock has a unique identifier known as block-id.  Its instantiation within a context of a course is identified by its usage-id.  A common class of xBlocks have the same defined type (or category) that indicate its common behavior and interface.  Some examples of xBlock types are: "course_info" (shared by Handouts and Announcements), "problem" (shared by all CAPA-based assessments), "video", "chapter" (a.k.a Section), and "sequential" (a.k.a. Subsection).

Access Control

Currently, access control checks are not governed by the xBlock, but by a higher-layer authorization framework in LMS.  A user's access to an xBlock varies depending on (a) their role, (b) their group membership, and (c) their individual settings and history.  Here are a few examples:

Views

Currently, an xBlock controls its own HTML rendering by returning HTML fragments in its implementations of "student_view", "studio_view", and/or "author_view" methods.  These HTML fragments are currently embedded inside LMS and Studio HTML pages and not independently viewed.

Requirements

Technical Requirements

Here are the basic technical requirements:

Non-Requirements

Use Cases

1. Mobile Apps

The initial primary clients of these new API endpoints are the edX Mobile apps as we embark on supporting interactive assessments on iOS and Android devices.  Our initial goals are to evolve the mobile app's simple-to-use video player to provide context and interactivity by adding further course structural context and basic assessment support.

The currently proposed UI requires presenting the following elements to the user:

 

      

2. Custom LMS Front-End

We can also imagine an ecosystem with other/extended front-end LMS subsystems that are optimized for different user experiences.  For example:

3. Displaying Individual xBlocks

The capability to render an individual xBlock can enable many different features.  For example:

4. Reuse and Performance Optimization for other LMS Features

Assuming that the new endpoints have been optimized for performance, they can be reused for other features in the edX Platform.  For example, the Bookmarks feature may want to quickly query information about a user's perception of an xBlock.

Related APIs

API Design

This section describes the overall design approach for the following set of APIs:

  1. A new generic Courses API as a residence for course-related endpoints.
  2. A new Course Blocks API that provides necessary data for creating courseware navigation and interaction.  This API is parameterized to support both user-specific and not-user-specific responses.
  3. A new xBlock URL that supports rendering of an individual xBlock. 

Generic APIs versus Mobile-specific APIs

First, a note on our overall approach for designing endpoints used by our mobile apps.  As we design APIs for mobile consumption, we try to abide by the following design constraints:

  1. Authentication: The API must support OAuth2 as an authentication mechanism as the mobile apps use the Bearer authentication scheme to transmit the openedX-issued OAuth2 access token.
  2. Authorization: The API must enforce server-side access control checks for all data access.
  3. Client/server division of labor: In general, business logic should be centralized on the server thereby allowing thinner clients and future maintainability.
  4. Performance:

While critical to the mobile experience, the above constraints can also be met by generic APIs that can be used by other (non-mobile) clients.  So going forward, we aim at creating generic APIs that can be consumed by both mobile and non-mobile clients.  However, if additional customized optimization is needed that is inherently mobile-specific, then we will implement a mobile-specific API as a layer above the generic one.

Courses API

 Having a multitude of endpoints and API resources for each type of data for a course can be both hard to maintain and difficult to understand for API consumers.  Instead, we have designed a top-level resource for courses, as follows.  The API is now documented on read-the-docs.

Note: The current Course Structure API would be renamed as below.

endpointdescriptionparametersresponse info

course catalog
api/courses/v1/courses/
 


Status: Implemented

returns a list of courses and their metadata

use cases:

  • course search page, course catalog - by accessing the endpoint as a non-privileged/anonymous user or passing in target user's username as a parameter
  • external privileged system enumerating through courses - by accessing the endpoint as a privileged user

note: for a list of enrolled courses, the enrollment API should be used instead.

  • user for a user-specific data
  • sort by date, name, org, etc.
  • paging
  • filters: mobile_only, category, etc.
  • if no user parameter is given, it lists all possible courses that the requested user can view.
  • if a user parameter is given, it lists only those courses that the target user can view.
  • each course's data response is as described in the course meta data endpoint below.

course metadata
api/courses/v1/courses/<course_id>


Status: Implemented

returns the meta data for the requested course

use cases: "course profile" information, like for a post on a social media page

user

id
name
start
end
image_url
updates_url
handouts_url
blocks_url
lms_web_url
about_url (drupal site)

course blocks
/api/courses/v1/blocks/<root_block_usage_id>/
?depth=all

or

/api/courses/v1/blocks/?course_id=<course_id>


Status: Implemented 

returns the blocks in the course starting at the requested root.

use cases: for accessing course content

user-specific
user=anjali

user-specific, mobile fields
user=anjali,
&fields=graded,format,multi_device,
&block_counts=video,
&student_view_data=video,
&student_view_data.video=mobile_low

all blocks for insights
fields=graded,format

 

FUTURE parameters
type - filter by block type

views other than student_view
A dictionary of blocks, with the key being the block’s usage_id and the value being the block’s data (as defined in the block data endpoint below).

course block data 
/api/courses/v1/blocks/<usage_id>/


Status: Not yet implemented

returns the data for the requested blocksame as for the course blocks endpoint

id
type
display_name
children
lms_web_url
olx_data
student_view_url
student_view_data

plus, requested fields that are supported, such as:

student_view_multi_device
graded
format
block_counts

course navigation
 

 

Status: Not approved

We will have FUTURE support for course navigation once it is designed.

returns the navigation information of the course starting at the requested root

use cases: for displaying the course hierarchy in a limited view with navigation constraints (e.g., rendering all blocks in a 3-level course hierarchy)

  

Block Rendering: Web, Responsive, and Native

As mentioned above, xBlocks currently manage the HTML rendering of their own data.  This work enhances that framework by introducing 2 additional viewing capabilities of an xBlock.  The API then provides freedom to the client on how to render the xBlock.

xBlock Views

View @supports(multi_device) decorator

Multi-device support is defined here as the functionality that provides (1) responsive web layouts, (2) support for touch-based inputs, and (3) interactive state management (hover, focus, etc) for various types and sized devices.

xBlock developers decorate the views that have multi-device support using a newly implemented @supports method decorator.  The existence of this decorator on the view indicate to the client whether the view's HTML has multi-device support.

class AnXBlockThatHasMultiDeviceSupport(XBlock):
	"""
	An xBlock whose student_view method returns HTML that is responsive to the user's device size.
	"""
	@XBlock.supports("multi_device")
	def student_view(self, context)
		"""
		This view's CSS/JS implementation has multi-device support, providing responsive and touch-sensitive HTML.
		"""
		pass

New student_view_data method

An xBlock that wants to enable other developers to implement their own view of the xBlock's data can implement a student_view_data method.  The semantics of the student_view_data method is analogous to the current student_view method on xBlocks, but it returns a JSON representation of the xBlock's data rather than a pre-formatted HTML rendering of the data.  This functionality supports native implementations of an xBlock.

class AnXBlockThatSupportsCustomizedStudentViews(XBlock):
	"""
	An xBlock that supports custom student views by implementing a student_view_json method.
	"""
	
	def student_view_data(self, context):
    	"""
    	Returns a JSON representation of the student_view of this block.
    	The contract of the JSON format should be published so it can be shared with the client.

		Arguments:
			context - is a JSON dict passed in by the client as request parameters to this block.
    	"""
		pass

Note: Consumers of this data will expect the same JSON representation from blocks of the same type.  So the following is recommended:

  1. Block types should be namespaced so there is no naming conflict between classes of xBlocks.
  2. JSON representation of a block type should be published and standardized, similar to the OLX standard, so there is a common standard for all xBlock developers and consumers.
  3. A block's JSON representation should be properly versioned for future compatibility.

View Options in the API

With the above viewing enhancements for an xBlock, there are now various choices for viewing an xBlock within the context of a course.  These comprehensive choices are provided to consumers of the Course Blocks API for their discretionary use, in the following fields.

Option 1: student_view_data: Native

If the client requests the JSON data for an xBlock type and that xBlock implements the student_view_data method, then the entire JSON data returned by this method is provided.  The client can then choose to natively render the xBlock for a more enriching user experience.  

If native rendering is not supported by either the xBlock or the client, then the client can fallback to one of the other options below.

Option2: student_view_url + student_view_multi_device: Responsive Web View

The student_view_url field provides a URL to render the individual xBlock without the envelope of the web LMS chrome.  The client can choose to use the student_view_multi_device property of the xBlock to determine whether or not to direct its users to the student_view_url

For example, the upcoming version of the mobile app will present the individual xBlock by navigating to the student_view_url in a Web View but only if the xBlock has student_view_multi_device.  Otherwise, it requires the user to fallback to the lms_web_url option below.

An alternative implementation could allow users (after warning them) to access the student_view_url even if the block does not have student_view_multi_device.

Option 3: lms_web_url: Fallback Web Browser

If all else fails, the lms_web_url provides a direct link to the navigational container of the xBlock on the web LMS.  The client can choose to present this option to the user as a fallback experience.

Course Blocks API

The crux of this proposal is the introduction of the Course Blocks endpoint that supports student-facing data for presenting course block content.  This section provides design considerations and then details of the endpoint for a user-specific request.  The API is now documented at read-the-docs.

FUTURE: Why Course Navigation?

We will have FUTURE support for course navigation once it is designed.

This proposal decouples the navigation of a course from the rest of the blocks in the course by considering Navigation as a formatting strategy that is applied to the course blocks.  In future extensions, one can envision different navigational strategies including flattening or deepening of the course structure or supporting a choose-your-own-adventure experience.

Additionally, in order to support clients that present a limited N-tier hierarchy of the course structure (e.g., Section->Subsection->Unit), the Navigation strategy can provide this information.  The server-side provides the logic of collapsing the DAG into an N-tiered hierarchy, allowing the client to be a generic consumer of this strategy.

No Pagination?

We made a conscious decision to not paginate this endpoint (for now) although its data could be potentially large, for the following reasons:

Mobile Considerations

Here are the points of consideration for each item listed in the mobile design constraints section above.

Authentication

The API requires OAuth2 or Session-based authentication to identify the user of the request.  Unauthenticated (guest) users are not allowed access. 

A 401 error is returned if authentication fails.

Authorization

The API makes the following access checks:

When there's an access control failure, the response payload will contain information about the specific error as described in has_access interface design.  It includes an error_code, developer_message, and a user_message.

Client/Server Separation of Concerns

Performance

Design

The API was designed with performance constraints in mind. 

Resources

Block

FieldTypeDescription
idstring

The usage-id of the block.

ex: "block-v1:edX+DemoX+Demo_Course+type@problem+block@45d46192272c4f6db6b63586520bbdf4"

typestring

The type of block. Possible values include course, chapter, sequential, vertical, html, problem, video, and discussion. The type can also be any custom block type used by the course.

display_namestringThe display name of the block.
childrenlist[string]

If the block has child blocks, a list of IDs of the child blocks.

Optional: Returned only if "children" is included in the "fields" parameter.

student_view_datadict

The JSON data of the student_view of this block.

Optional: Returned only if the "student_view_data" input parameter contains this block's type.

student_view_urlstring

The URL to retrieve the HTML rendering of this block's student view.  The HTML could include CSS and Javascript code. This field can be used in combination with the student_view_multi_device field to decide whether to display this content to the user.

This URL can be used as a fallback if the student_view_data for this block type is not supported by the client or the block.

student_view_multi_deviceboolean

Whether or not the block's rendering obtained via student_view_url is responsive.

Optional: Returned only if "student_view_multi_device" is included in the "fields" parameter.

lms_web_urlstringThe URL to the navigational container of the xBlock on the web LMS. This URL can be used as a further fallback if the student_view_url and the student_view_data fields are not supported.
formatstring

The assignment type of the block. Possible values can be "Homework", "Lab", "Midterm Exam", and "Final Exam".

Optional: Returned only if "format" is included in the "fields" parameter.

Aggregate values

gradedboolean

Whether or not the block or any of its descendants is graded.

Optional: Returned only if "graded" is included in the "fields" parameter.

block_countsdict

For each block type specified in the block_counts parameter to the endpoint, the aggregate number of blocks of that type for this block and all of its descendants.

Optional: Returned only if the "block_counts" input parameter contains this block's type.

Video Block

The following fields are associated with a block of type "video" and thus returned in the student_view_data value for a video block type.

FieldTypeDescription
durationintegerThe length of the video, if available
only_on_webbooleanWhether or not the video is accessible only on the website (per licensing constraints)
transcriptsdict

A dict of language codes (key) and URLs (value) to available video transcripts

encoded_videosdictA dict of encoded videos keyed by video profile type

Encoded Video

FieldTypeDescription
profile_namestringProfile name of the encoding
urlstringURL to the video file
sizeintegerSize of the video file

Endpoints

BLOCKS: /api/courses/v1/blocks/?root=<usage_id> 

MethodDescription
GET

Retrieves the blocks in a course

 Query parameters:

  • student_view_data: (list) Indicates for which block types to return student_view_data.
    example: student_view_data=video
  • student_view_data.<block_type>.context(string) Data to be passed as the "context" parameter to the given block type's student_view_data method.
    example: student_view_data.video.context="mobile_low"
  • block_counts: (list) Indicates for which block types to return the aggregate count of the blocks.
    example: block_counts=video,problem
  • fields: (list) Indicates which additional fields to return for each block.
    default: children,graded,format,student_view_multi_device
  • user: (string) the username of the user that should be used as the context of the request. 
    The response is created according to this user's access, group affiliation, and individual differentials.

Returns:

  • root: (string) The usage-id of the root block in the response.
  • blocks: (dict) A dictionary where the key is the block's usage-id and the value is the block's data.  
    • The fields returned for the block are described in the Block table above. 

Click for example (older version of the API)


FUTURE: NAVIGATION

MethodDescription
GET

We will have FUTURE support for course navigation once it is designed.

Returns a navigation strategy for the course to create a course outline until the requested maximum depth.  All nodes past the maximum depth are collapsed into their container's descendants field.

 Query parameters:

  • navigation_depth (integer) Indicates how far deep to traverse into the course hierarchy before bundling all the descendants.
    default: 3 since typical navigational views of the course show a maximum of chapter->sequential->vertical.
    example: navigation_depth=3

Returns:

  • root: (string) The usage-id of the root block in the course.
  • navigation: (dict) A dictionary where the key is the block's usage-id and the value is the block's data.
    • Only the "descendants" field of the block is returned. The "descendants" field is described in the Block table above.

Click for example

Example of API call from Mobile Apps

Here is the expected API call that the mobile app makes on the blocks endpoint:

/api/courses/v1/blocks?root=<usage_id>/?user=<user_name>&block_counts=video&student_view_data=video&student_view_data.video.context=mobile_low&fields=graded,format,student_view_multi_device

XBlock URL

The following new xBlock URL supports HTML rendering of an individual xBlock without the chrome envelope of the LMS courseware.  This URL is the value for the student_view_url API field mentioned earlier.

/xblock/{usage_id}?view=student_view

Summary