-
Notifications
You must be signed in to change notification settings - Fork 13
Draft API Spec
This document is copied from Apiary, and the canonical version lives there. This page is more easily edited and referenced; apiary's design is optimized for APIs, but comments are lost easily. If you wish to comment on part of the API, please do it on this document by editing the page and adding your comment, prefixed with your Github username, like this:
@singingwolfboy: here's an example of a comment.
@ormsbee: As a sort of meta-comment about the API as a whole -- I would really like to see use cases here for the various API calls. Not use cases as in "I would like to see a list of courses", but use cases as in "the LMS needs to render a list of active courses that can be filtered on the following things for display on XYZ pages". Maybe this is already internalized for you folks since you're coming at this from the studio side of things, but in many cases it's not clear to me. For instance, when I think of snapshots, getting them by ID is definitely good, but one of the first things that comes to mind is a researcher being able to say "Hey, that's a funny pattern in the event logs -- get me the snapshot of this course as it existed at this timestamp." or "Get me all the snapshots that were live between X and Y times, along with the times they became live."
The edX API is designed to allow clients to introspect and manipulate XBlocks and their related models.
Conceptually, an XBlock is any component that knows how to render itself, at least in a certain context. XBlocks can contain other XBlocks. XBlocks can define their own schema for storing data, which must consist only of primitive types (string, int, list, mapping)
Note: This API is read-only. XBlock types cannot be created, modified, or deleted through this API; available XBlock types are solely controlled by the server administrator(s). Other XBlock types may exist on other servers, but these API responses will only contain information about the XBlock types that this server supports.
-
Response 200 (application/json)
[{ "id": "thumbs", "title": "Thumbs", "description": "a simple control to indicate thumbs-up or thumbs-down, and aggregate responses", "schema": {}, }, { "id": "randomize", "title": "Randomize", "description": "randomize children", "schema": {} }, { "id": "schema_ex", "title": "Schema Type Example", "description": "just demonstrates all the different schema types", "schema": { "name": "string", "age": "int", "my_dict": { "a": "string" }, "list_of_strings": ["string"], "list_of_ints": ["int"] } }]
@ormsbee: Why are we exposing the XBlock Type's schema?
@ormsbee: Will XBlock Types have versions? Authors?
@ormsbee: What is the use case for this? Studio querying to see what XBlock types are available for authoring? If so, does it need any additional information about how to categorize them?
- Parameters
- id (required, string,
schema_ex
) The ID of the XBlock type; usually a short lowercase string.
- id (required, string,
-
Response 200 (application/json)
{ "id": "schema_ex", "title": "Schema Type Example", "description": "just demonstrates all the different schema types", "schema": { "name": "string", "age": "int", "my_dict": { "a": "string" }, "list_of_strings": ["string"], "list_of_ints": ["int"] } }
@ormsbee: Since this is the exact same information as what's in the listing, why would someone want to use this? Wouldn't they typically come through the list view to get here?
@ormsbee: I'm not sure if this is within the scope of the API, but once I'm at a detail view for an XBlock type, what can I do with this information? Is there a resource that can be linked off of here that would bring me to something where I could create a new content piece based off of this XBlock type? See its editor? A sample problem?
Conceptually, an index is simply a mapping of branches (such as "live", "draft", "honors", etc) to the latest snapshot for that branch. Indexes also contain permission information for who can read the index, and who can modify its contents (or the contents of its child snapshots).
A Course is the definitive example of an index, but other types of indexes could also exist.
@ormsbee: The term "index" is really generic and only makes sense to people if they know git (and even then, it's not really the same thing). If the reason we're not using the term "course" is because we want to allow for things that are smaller than courses, then let's talk to the folks in services and come up with an acceptable generic term that covers both courses and smaller units of instruction.
-
Response 200 (application/json)
[{ "id": "myu.compsci.db.sql.t1_2014", "status": "active", "created_by": 84, "created_on": "2013-05-18T07:20:51Z", "starts_on": "2013-06-18T07:20:51Z", "ends_on": "2013-05-18T07:20:51Z", "enrollment_starts_on": "2013-05-18T07:20:51Z", "enrollment_ends_on": "2013-05-18T07:20:51Z", "permissions": { "read": { "user": [84], "group": [], "world": false }, "write": { "user": [84], "group": [], "world": false } }, "branches": { "live": "1c82df57-6b6d-47a7-9f31-24c19d6c6236", "draft": "19450641-4f77-4646-a78e-6ee07a784fb3" }, "display": { "name": "Intro to SQL", "organization": "My University", "number": "101X", "run": "Fall 2014", "image": "/v1/assets/845/raw", "summary": "A short description of the course", "description": "A longer description of the course" } }, { "id": "myu.compsci.db.sql.t1_2015", "status": "development", "created_by": 83, "created_on": "2013-05-16T17:10:31Z", "starts_on": "2013-06-18T07:20:51Z", "ends_on": "2013-05-18T07:20:51Z", "enrollment_starts_on": "2013-05-18T07:20:51Z", "enrollment_ends_on": "2013-05-18T07:20:51Z", "permissions": { "read": { "user": [83], "group": [], "world": false }, "write": { "user": [83], "group": [], "world": false } }, "branches": { "live": "6173b78b-cc3e-440a-b84f-aed720f320e6", "draft": "cca0d370-37be-4168-90c3-7fc4a818e8fc", "honors": "29210e12-66c0-4dba-ac61-a74c35cbdc4e" }, "display": { "name": "Intro to SQL", "organization": "My University", "number": "101X", "run": "Fall 2015", "image": "/v1/assets/847/raw", "summary": "A short description of the course", "description": "A longer description of the course" } }, { "id": "anotheru.english.shakespeare.Spring2012", "status": "finished", "created_by": 56, "created_on": "2013-11-10T09:20:20Z", "starts_on": "2013-06-18T07:20:51Z", "ends_on": "2013-05-18T07:20:51Z", "enrollment_starts_on": "2013-05-18T07:20:51Z", "enrollment_ends_on": "2013-05-18T07:20:51Z", "permissions": { "read": { "user": [56], "group": [], "world": false }, "write": { "user": [56], "group": [], "world": false } }, "branches": { "live": "da8e5827-0fd0-4fb3-8ce4-a163598130e0", "reading_group": "624133f6-3a7a-43e7-afc9-d30824f24b28" }, "display": { "name": "Intro to Shakespeare", "organization": "Another University", "number": "101X", "run": "Spring 2012", "image": "/v1/assets/102/raw", "summary": "A short description of the course", "description": "A longer description of the course" } }]
@ormsbee: Why not use a querystring param here? Having indexes/active as a list but indexes/{id} as a detail seems unnecessarily inconsistent.
This API response only returns information about indexes with the status "active". Other indexes (for example, completed courses, courses still under development, etc) will not be returned by this endpoint.
-
Response 200 (application/json)
[{ "id": "myu.compsci.db.sql.t1_2014", "status": "active", "created_by": 84, "created_on": "2013-05-18T07:20:51Z", "starts_on": "2013-06-18T07:20:51Z", "ends_on": "2013-05-18T07:20:51Z", "enrollment_starts_on": "2013-05-18T07:20:51Z", "enrollment_ends_on": "2013-05-18T07:20:51Z", "permissions": { "read": { "user": [], "group": [], "world": false }, "write": { "user": [], "group": [], "world": false } }, "branches": { "live": "1c82df57-6b6d-47a7-9f31-24c19d6c6236", "draft": "19450641-4f77-4646-a78e-6ee07a784fb3" }, "display": { "name": "Intro to SQL", "organization": "My University", "number": "101X", "run": "Fall 2014", "image": "/v1/assets/102/raw", "summary": "A short description of the course", "description": "A longer description of the course" } }]
Returns a qualified list of indexes as specified by a partial ID. This allows
API clients to filter API responses based on organization, department, etc.
This is a simple string prefix match, but the match must be followed either
by a dot or by the end of the string. For example, if the partial_id
is "mit.eecs",
then "mit.eecs.7001X" and "mit.eecs.8910X.Dec2014" would match, but
"mit.eecs7001X" would not match, nor would "harvard.mit.eecs"
- Parameters
- partial_id (optional, string,
myu.compsci
)
- partial_id (optional, string,
-
Response 200 (application/json)
[{ "id": "myu.compsci.db.sql.t1_2014", "status": "active", "created_by": 84, "created_on": "2013-05-18T07:20:51Z", "starts_on": "2013-06-18T07:20:51Z", "ends_on": "2013-05-18T07:20:51Z", "enrollment_starts_on": "2013-05-18T07:20:51Z", "enrollment_ends_on": "2013-05-18T07:20:51Z", "permissions": { "read": { "user": [], "group": [], "world": false }, "write": { "user": [], "group": [], "world": false } }, "branches": { "live": "1c82df57-6b6d-47a7-9f31-24c19d6c6236", "draft": "19450641-4f77-4646-a78e-6ee07a784fb3" }, "display": { "name": "Intro to SQL", "organization": "My University", "number": "101X", "run": "Fall 2014", "image": "/v1/assets/102/raw", "summary": "A short description of the course", "description": "A longer description of the course" } }, { "id": "myu.compsci.db.sql.t1_2015", "status": "development", "created_by": 84, "created_on": "2013-05-18T07:20:51Z", "starts_on": "2013-06-18T07:20:51Z", "ends_on": "2013-05-18T07:20:51Z", "enrollment_starts_on": "2013-05-18T07:20:51Z", "enrollment_ends_on": "2013-05-18T07:20:51Z", "permissions": { "read": { "user": [], "group": [], "world": false }, "write": { "user": [], "group": [], "world": false } }, "branches": { "live": "6173b78b-cc3e-440a-b84f-aed720f320e6", "draft": "cca0d370-37be-4168-90c3-7fc4a818e8fc", "honors": "29210e12-66c0-4dba-ac61-a74c35cbdc4e" }, "display": { "name": "Intro to SQL", "organization": "My University", "number": "101X", "run": "Fall 2015", "image": "/v1/assets/987/raw", "summary": "A short description of the course", "description": "A longer description of the course" } }]
- Parameters
- id (required, locator string,
arizona.latin.spring-2014
)
- id (required, locator string,
Create a new index with the information provided. An index can only
be created at the given ID if the user sending the API request has
permission to administer the fully-qualified identifier. For example,
a user could not create a course under the mit
namespace unless
the user has permission to modify that namespace. New namespaces
can be arbitrarily created by anyone.
The "id" parameter in the request is optional; if specified, it must match the id in the URL for this request. The "branches" and "permissions" maps are both optional. If the "branches" is not included in the request; it will be populated by the server with one branch named "draft". If the "permissions" map is not included in the request, the default permissions are read and write access for the user that created the index, and no other permissions for anyone.
-
Request (application/json)
{ "id": "arizona.latin.spring-2014", "status": "development" }
-
Response 201 (application/json)
{ "id": "arizona.latin.spring-2014", "status": "development", "created_by": 89, "created_on": "2013-11-20T14:15:16Z", "starts_on": null, "ends_on": null, "enrollment_starts_on": null, "enrollment_ends_on": null, "permissions": { "read": { "user": [89], "group": [], "world": false }, "write": { "user": [89], "group": [], "world": false } }, "branches": { "draft": "0d72a223-8b56-417d-9f5d-dfacc5955f2d" }, "display": {} }
-
Response 200 (application/json)
{ "id": "arizona.latin.spring-2014", "status": "development", "created_by": 89, "created_on": "2013-11-20T14:15:16Z", "starts_on": null, "ends_on": null, "enrollment_starts_on": null, "enrollment_ends_on": null, "permissions": { "read": { "user": [89], "group": [], "world": false }, "write": { "user": [89], "group": [], "world": false } }, "branches": { "live": "6173b78b-cc3e-440a-b84f-aed720f320e6", "draft": "cca0d370-37be-4168-90c3-7fc4a818e8fc", "honors": "29210e12-66c0-4dba-ac61-a74c35cbdc4e" } }
-
Request (application/json)
{ "status": "cancelled" }
-
Response 200 (application/json)
{ "id": "arizona.latin.spring-2014", "status": "cancelled", "created_by": 89, "created_on": "2013-11-20T14:15:16Z", "starts_on": null, "ends_on": null, "enrollment_starts_on": null, "enrollment_ends_on": null, "permissions": { "read": { "user": [89], "group": [], "world": false }, "write": { "user": [89], "group": [], "world": false } }, "branches": { "live": "6173b78b-cc3e-440a-b84f-aed720f320e6", "draft": "cca0d370-37be-4168-90c3-7fc4a818e8fc", "honors": "29210e12-66c0-4dba-ac61-a74c35cbdc4e" } }
Note that a DELETE request to an index will not change its status
attribute to "deleted" -- it will really, truly delete the index.
Subsequent GET requests to the index's former ID will return an
HTTP 404 status code. To update the status
attribute, use a PUT
request to partially update the index.
-
Response 200
{"message": "deleted"}
- Parameters
- id (required, string,
myu.compsci.db.sql.t1_2014
)
- id (required, string,
-
Response 200 (application/json)
{ "live": "6173b78b-cc3e-440a-b84f-aed720f320e6", "draft": "cca0d370-37be-4168-90c3-7fc4a818e8fc", "honors": "29210e12-66c0-4dba-ac61-a74c35cbdc4e" }
-
Request (application/json)
{ "live": "cca0d370-37be-4168-90c3-7fc4a818e8fc" }
-
Response 200 (application/json)
{ "live": "cca0d370-37be-4168-90c3-7fc4a818e8fc", "draft": "cca0d370-37be-4168-90c3-7fc4a818e8fc", "honors": "29210e12-66c0-4dba-ac61-a74c35cbdc4e" }
- Parameters
- id (required, string,
myu.compsci.db.sql.t1_2014
) - name (required, string,
live
)
- id (required, string,
- Response 302
-
Headers
Location: /v1/snapshots/cca0d370-37be-4168-90c3-7fc4a818e8fc
-
Body
{"id": "cca0d370-37be-4168-90c3-7fc4a818e8fc"}
-
Point the branch at a new snapshot identified by the given ID. If the given ID does not refer to an existing snapshot, this will fail with a 400 status code.
-
Request (text/plain)
29210e12-66c0-4dba-ac61-a74c35cbdc4e
-
Response 200 (application/json)
{"message": "updated"}
An index must have at least one branch in it. If an API request attempts to delete the last branch in an index, the request will fail with an HTTP 400 status code.
-
Response 200
{"message": "deleted"}
A snapshot provides a versioned dictionary of all blocks directly included in a courseware subtree with their settings, children references, and edit info. It also includes pointers to the parent snapshot, the ancestor snapshot, the index that owns it, the user who created this snapshot.
Snapshots are immutable -- any operation to "modify" an existing snapshot will create a new snapshot instead. When a snapshot is created, it copies the permissions mapping from the index that owns it at the moment of its creation. Indexes may have their permissions change, but the permissions on a particular snapshot are set at its creation and may never change.
- Parameters
- id (required, UUID,
5884ec28-f2a8-4735-a9f9-d54158405af5
)
- id (required, UUID,
-
Response 200 (application/json)
{ "id": "b20693ac-0dbd-4d4f-8740-e29bfb965409", "parent": "5d566816-e5db-4506-9ab3-5cba6ff972ef", "ancestor": "560dbc35-de74-4801-83bd-73b4bddc7594", "index": "myu.compsci.db.sql.t1_2014", "created_by": 89, "created_on": "2013-10-24T16:14:53Z", "permissions": { "read": { "user": [89], "group": [], "world": false }, "write": { "user": [89], "group": [], "world": false } }, "root_xblock": "head12345", "xblocks": { "head12345": { "name": "Root Node", "children": ["chapter1", "chapter2"] }, "chapter1": { "name": "Chapter One", "children": ["chapter3"] } "chapter2": { "name": "Chapter Two", "children": [] }, "chapter3": { "name": "Chapter Three", "children": [] } } }
-
Request (application/json)
{ "xblocks": { "chapter3: { "name": "the REAL chapter three" } } }
-
Response 201 (application/json)
-
Headers
Location: /v1/snapshot/91d7000c-2685-4e20-a2f0-ab9e5d1428ec
-
Body
{ "message": "created", "location": "/v1/snapshot/91d7000c-2685-4e20-a2f0-ab9e5d1428ec" }
-
A list of the assets that are referenced in this snapshot. If the user is authenticated and a part of the index, this list will contain locked (private) assets, as well.
-
Response 200 (application/json)
[{ "id": 1, "filename": "edx-logo.png", "type": "image/pdf" }, { "id": 18, "filename": "edx101-intro.mov", "type": "video/quicktime" }]
- Parameters
- id (required, UUID,
5884ec28-f2a8-4735-a9f9-d54158405af5
)
- id (required, UUID,
-
Response 200 (application/json)
{ "head12345": { "name": "Root Node", "children": ["chapter1", "chapter2"] }, "chapter1": { "name": "Chapter One", "children": ["chapter3"] } "chapter2": { "name": "Chapter Two", "children": [] }, "chapter3": { "name": "Chapter Three", "children": [] } }
- Parameters
-
id (required, UUID,
5884ec28-f2a8-4735-a9f9-d54158405af5
) -
type_id (optional, string,
video
)The type_id must match one of the XBlock Type IDs.
-
-
Response 200 (application/json)
{ "chapter1": { "name": "Chapter One", "children": ["chapter3"] } "chapter3": { "name": "Chapter Three", "children": [] } }
Like snapshots, XBlock instances are immutable. Any operation that would modify an existing XBlock instance instead creates a new instance, and returns a reference to that newly-created instance.
- Parameters
- id (required, UUID,
a7e3233a-c19d-40d4-b450-2046bd099501
) The ID of the snapshot that contains this xblock, usually a UUID. - name (required, string,
chapter7
) The name of the xblock instance contained in the snapshot
- id (required, UUID,
Note that the id
and parent
fields are IDs and not URLs, even though they
may resemble URLs. That's why they do not start with /v1
.
-
Response 200 (application/json)
{ "id": "/snapshots/a7e3233a-c19d-40d4-b450-2046bd099501/xblocks/chapter7", "type": "schema_ex", "parent": "/snapshots/e78ff15e-da0b-4d77-845e-30a30d265106/xblocks/chapter7", "children": [], "name": "my_name", "age": 30, "my_dict": { "a": "b" }, "list_of_strings": ["foo", "bar", "baz"], "list_of_ints": [1, 2, 3, 4, 5] }
Note that this will create a new snapshot based on this snapshot, and a new XBlock instance based on this XBlock instance. The response is simply a pointer to the newly-created XBlock instance under the newly-created snapshot.
-
Request (application/json)
{"name": "a_different_name"}
-
Response 201 (application/json)
-
Headers
Location: /v1/snapshots/b6bbab4a-3a21-485e-ab41-094488ae0847/xblocks/chapter7
-
Body
{ "message": "created", "location": "/v1/snapshots/b6bbab4a-3a21-485e-ab41-094488ae0847/xblocks/chapter7" }
-
An XBlock instance can contain a lot of information. To reduce the size of the response, a client can specify that it is only interested in a subset of the fields in the XBlock instance. The API response will then only return those fields.
- Parameters
- id (required, UUID,
a7e3233a-c19d-40d4-b450-2046bd099501
) The ID of the snapshot that contains this xblock, usually a UUID. - name (required, string,
chapter7
) The name of the xblock instance contained in the snapshot - field_list (optional, comma-separated list of strings,
name,age
) A comma-separated list of field names to include in the response to this request. If thefield_list
attribute is specified, any fields not included in thefield_list
will not be included in the response.
- id (required, UUID,
-
Response 200 (application/json)
{ "name": "my_name", "age": 30 }
Anyone who uses edX: a learner, course-creator, content author, etc.
Note that the GET verb is not currently supported for this API; due to privacy concerns, it is not possible to get a list of all users in the system.
-
Request (application/json)
{ "first_name": "Cookie", "last_name": "Monster", "roles": ["learner"] }
-
Response 201 (application/json)
-
Headers
Location: /v1/users/35
-
Body
{ "message": "created", "location": "/v1/users/35" }
-
Comment
-
Response 200 (application/json)
[{ "id": 1, "first_name": "Anant", "last_name": "Agarwal", "roles": ["admin"] }, { "id": 2, "first_name": "Joe", "last_name": "Learner", "roles": ["learner"] }, { "id": 3, "first_name": "Sarah", "last_name": "Staff", "roles": ["course_creator", "learner"], }]
-
-
- Parameters
- id (required, int,
1
)
- id (required, int,
-
Response 200 (application/json)
{ "id": 1, "first_name": "Anant", "last_name": "Agarwal", "roles": ["admin"] }
-
Request (application/json)
{"first_name": "Bigshot"}
-
Response 200 (application/json)
{ "id": 1, "first_name": "Bigshot", "last_name": "Agarwal", "roles": ["admin"] }
-
Response 200 (application/json)
{"message": "deleted"}
Groups of users
List existing groups
-
Response 200 (application/json)
[{ "id": 1, "users": [1,2,3] }, { "id": 2, "users": [5, 10, 1] }]
Create a new group.
-
Request (application/json)
{"users": [100, 4, 59, 3]}
-
Response 201 (application/json)
-
Headers
Location: /v1/groups/7
-
Body
{ "message": "created", "location": "/v1/groups/7" }
-
- Parameters
- id (required, int,
7
)
- id (required, int,
-
Response 200 (application/json)
{ "id": 7, "users": [100, 4, 59, 3] }
-
Request (application/json)
{"users": [100, 4, 59]}
-
Response 200 (application/json)
{ "id": 7, "users": [100, 4, 59] }
-
Response 200 (application/json)
{"message": "deleted"}
Images, video, audio, etc
Note that there is no API to get a list of private assets
This creates a placeholder entry, with size 0.
-
Request (application/json)
{ "filename": "hypnotoad.gif", "type": "image/gif" }
-
Response 201 (application/json)
-
Headers
Location: /v1/assets/7463
-
Body
{ "message": "created", "location": "/v1/assets/7463" }
-
Size is in bytes.
-
Response 200 (application/json)
[{ "id": 1, "filename": "edx-logo.png", "type": "image/png", "size": 2045, "locked": false }, { "id": 2, "filename": "edx-docs.pdf", "type": "application/pdf" "size": 573892, "locked": false }, { "id": 7463m "filename": "hypnotoad.gif", "type": "image/gif", "size": 0, "locked": false }]
- Parameters
- id (required, int,
1
)
- id (required, int,
-
Response 200 (application/json)
{ "id": 1, "filename": "edx-logo.png", "type": "image/png", "size": 2045, "locked": false }
Note that you cannot update the "size" attribute using this API, only by uploading a new file content.
-
Request (application/json)
{"locked": "true"}
-
Response 200 (application/json)
{ "id": 1, "filename": "edx-logo.png", "type": "image/png", "size": 2045, "locked": true }
-
Response 200 (application/json)
{"message": "deleted"}
- Parameters
- id (required, int,
1
)
- id (required, int,
-
Response 200 (image/png)
PNG content goes here
-
Request (image/png)
PNG content goes here
-
Response 200 (application/json)
{"message": "uploaded"}
-
Response 200 (application/json)
{"message": "erased"}