Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • Nice: Do not expose database IDs where possible (Must for external APIs, per dev ops)
  • Must: edX resource identifiers
    • Users should be referenced by username.

    • Courses runs should be referenced via course run keys (eg. course-v1:edX+BlendedX+1T2018)
    • Catalog courses should be referenced via a catalog UUID.
    • Course blocks should be referenced via usage keys (eg. block-v1:org+course+run+type@sequential+block@2aa6fc9d8278)
  • Explicit Filters
    • Model system resource URL schemes as if all resources are available to all users
    • Include all necessary filters in the URL such that any user could theoretically access the resource
    • Anchor
      username
      username
      Separate filtering and authorization – ie, do not return different resource representations via the same URL based on the requesting user 
      • Example 1:  Choose "/profiles/john_harvard" over "/profile"
      • Example 2:  Choose "/courses?username=john_harvard" over "/courses"
    • See relevant conversation here for more context.
    • Remember, it's entirely possible that "/profiles/john_harvard" or "/courses?username=john_harvard" could be requested by the "administrator" user

    • Several benefits exist from an explicit filtering approach:
      • Ensures resources/results are individually-addressable
      • Enables discovery/sharing of resources, among other potential uses
      • Resource filtering mechanisms can be modified without impacting authorization mechanisms
      • Intermediate network gear can cache resource representations to improve performance (for open/unprotected resources)

  • Composite Resource (with multiple dimensions)
    • If an endpoint represents a relationship among multiple dimensions, the dimensions can be specified in the following ways:
    • As filter parameters:
      • /api/enrollments/v1/enrollments/?user={username}&course={course_id}
    • As comma-delimited resource keys in the URL:
      • /api/enrollments/v1/enrollments/{username},{course_id}
    • As a UUIDs to uniquely identify the relationship:
      • /api/enrollments/v1/enrollments/{enrollment_id}

...

  • HTTP status codes - Use the appropriate value amongst the following (or document in the code why an exception is needed)

    • 200 - OK
    • 201 - Created
    • 204 - OK, no content returned (use for PATCH)
    • 304 - Not Modified
    • 400 - Bad Request
    • 401 - Unauthorized (for unauthenticated users)
    • 403 - Forbidden (for authenticated users who do not have the right permissions)
    • 404 - Not Found
    • 415 - Unsupported Media Type (used for PATCH if implementation is "merge patch" algorithm, and caller did not specify "application/merge-patch+json" content_type).
    • 500 - Internal Server Error
  • Prevent information leakage
    • Must: Use 404 instead of 403 when the actual existence would be leaking information that we don't want - Dave O.

  • Error Description

    • Must: Be verbose and use plain language descriptions.

    • Must: Use i18n for user facing messages ("user_message" in example below)
    • Nice: Add as many hints as your API team can think of about what's causing an error.

    • Nice: Add a link in your description to more information, like Twilio does.

  • Error format:

    • developer_message (no i18n)

    • user_message(optional, but if provided, i18n as the expectation is that this may surface in a UI)

    • field_errors (if applicable)

    • error_code (for example: see has_access interface design)  Include description in your REST API Docs.

      Code Block
      {
      	"error_code": "course_not_started"  # a short string that the client can rely upon for handling different errors
      	"developer_message" : "Verbose, plain language description of the problem for the app developer with hints about how to fix it.", 
      	"user_message":"Pass this message on to the app user if needed.", 
          "field_errors": {
              "foo": {
                  "developer_message": "",
                  "user_message": ""
              }
          }
      }


...