This is a detailed design document on the Course Blocks API and how it enables xBlocks on Mobile.
To provide a REST interface for accessing course structure and course blocks for a user.
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.
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.
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).
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:
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.
Here are the basic technical requirements:
It should be possible to delegate the rendering of an xBlock to the client by providing the xBlock's raw data (e.g., in JSON). This allows us to support:
a user experience that is native to the device.
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:
We can also imagine an ecosystem with other/extended front-end LMS subsystems that are optimized for different user experiences. For example:
The capability to render an individual xBlock can enable many different features. For example:
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.
This section describes the overall design approach for the following set of 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:
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.
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.
endpoint | description | parameters | response info |
---|---|---|---|
course catalog Status: Implemented | returns a list of courses and their metadata use cases:
note: for a list of enrolled courses, the enrollment API should be used instead. |
|
|
course metadata 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 |
course blocks 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-specific, mobile fields all blocks for insights FUTURE parameters | 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 Status: Not yet implemented | returns the data for the requested block | same as for the course blocks endpoint | id plus, requested fields that are supported, such as: student_view_multi_device |
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) |
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.
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 |
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:
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.
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.
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.
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.
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.
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.
We made a conscious decision to not paginate this endpoint (for now) although its data could be potentially large, for the following reasons:
Here are the points of consideration for each item listed in the mobile design constraints section above.
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.
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.
The API was designed with performance constraints in mind.
Field | Type | Description |
---|---|---|
id | string | The usage-id of the block. ex: "block-v1:edX+DemoX+Demo_Course+type@problem+block@45d46192272c4f6db6b63586520bbdf4" |
type | string | 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_name | string | The display name of the block. |
children | list[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_data | dict | 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_url | string | 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_device | boolean | 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_url | string | The 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. |
format | string | 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 | ||
graded | boolean | Whether or not the block or any of its descendants is graded. Optional: Returned only if "graded" is included in the "fields" parameter. |
block_counts | dict | 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. |
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.
Field | Type | Description |
---|---|---|
duration | integer | The length of the video, if available |
only_on_web | boolean | Whether or not the video is accessible only on the website (per licensing constraints) |
transcripts | dict | A dict of language codes (key) and URLs (value) to available video transcripts |
encoded_videos | dict | A dict of encoded videos keyed by video profile type |
Field | Type | Description |
---|---|---|
profile_name | string | Profile name of the encoding |
url | string | URL to the video file |
size | integer | Size of the video file |
BLOCKS: /api/courses/v1/blocks/?root=<usage_id>
Method | Description |
---|---|
GET | Retrieves the blocks in a course Query parameters:
Returns:
|
FUTURE: NAVIGATION
Method | Description |
---|---|
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:
Returns:
|
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
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