Skip to content

Add first draft of OEP-13 (API conventions)#36

Merged
andy-armstrong merged 3 commits intomasterfrom
efagin/oep-13-api-conventions
Jul 25, 2017
Merged

Add first draft of OEP-13 (API conventions)#36
andy-armstrong merged 3 commits intomasterfrom
efagin/oep-13-api-conventions

Conversation

@efagin
Copy link
Contributor

@efagin efagin commented Dec 29, 2016

Supercedes https://openedx.atlassian.net/wiki/display/AC/edX+REST+API+Conventions (the content is virtually identical). A Best Practices OEP is a more reasonable home for this content and I'd like changes to our conventions to be captured more formally (i.e. through PRs instead of wiki comment threads).

@nasthagiri, would you mind acting as arbiter for this OEP? I can't imagine there are any issues but you're familiar enough with the original source wiki. Once this gets merged, I'm going to update the original wiki page to just link to the OEP.

@efagin efagin force-pushed the efagin/oep-13-api-conventions branch from 41871b6 to 6abc23a Compare December 29, 2016 19:54
Copy link
Contributor

@andy-armstrong andy-armstrong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@efagin converting this to an OEP was a great idea, thanks. I'm out of the loop on our current thinking around API development so I look forward to hearing how others react. I have a few minor comments that I hope are helpful.

Motivation
==========

The Open edX platform contains many extension points for third-party developers that wish to integrate with the platform. We wish to approach a standard methodology for API design in order to give developers more consistency in their API client design, and to make our endpoint behaviors more predictable.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: we settled on wrapping lines at 80 characters in OEPs.

From @cpennington:

I tend to prefer wrapped lines in the raw text, simply because it's easier to read in an editor (and in the email summaries that github sends). Github wraps them nicely in the diff, but in this case I lean towards optimizing towards the lowest common denominator.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it would be helpful to have a description of the API gateway and how (if?) it affects the development of APIs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I just updated the doc with 80-char line wrapping.


**Discoverable**

Support `HATEOAS <https://en.wikipedia.org/wiki/HATEOAS>`_ where possible. This allows us to change our URLs without needing to worry about updating the mobile apps if the app discovers its URLs from a base URL.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we using HATEOAS in our newer APIs? I remember that @nasthagiri mentioned there were reasons why mobile doesn't use it. Is this still the recommendation? Does it change with the API gateway?


*Must*: edX resource identifiers

- Users should be referenced by username
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this where we landed at the last arch lunch?


- ``expand`` parameter - Allow clients to request including data from other resources using the expand parameter as explained further in the Expansion section.

.. todo: link to expansion section
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to provide this link

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, done.


Use the appropriate value amongst the following (or document in the code why an exception is needed)

200 - OK
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this section shows up as quoted on the rendered page:

https://github.com/edx/open-edx-proposals/blob/6abc23aed18fe98f0270934363d744fc3ef2cdec/oeps/oep-0013.rst

I'd probably also bold the status codes themselves.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

{
"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.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: missing a space between the key and value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Documentation
-------------

Work with the Docs team to update the `edX platform API documentation <http://edx-platform-api.readthedocs.org/en/latest/>`_.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this document is still being updated, and it if it is then it is not the docs team that does it.

- *Must*: Additive changes to the contract of the API, or the results, should not bump the major version, unless those changes are non-optional, and break existing contracts with the API.


**Future considerations**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe pull this out to its own top level section? I thought there was a standard Future Directions in OEP-1 but I don't see one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed it entirely, we should keep speculative things out of OEPs and just add content when it's well-formed.

Authentication
--------------

By convention, our REST APIs support the following two authentication schemes:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be useful to mention JWT tokens here.

Reference Implementation
========================

There are a number of existing APIs that you can crib from, for example:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to update this to include some of the newer APIs, such as those for course discovery.

- ``fields`` parameter - Allow clients to specify/filter the fields in the response by supporting a fields parameter as a comma-delimited list. ::

/dogs?fields=name,color,location
/dogs?fields=title,media:group(media:thumbnail)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I don't think we have implemented the xpathesque type of field filtering that Google has.
  2. If we think we want to use this, for mobile or otherwise, we should choose a solution and duplicate and/or link to docs that provide details. For example, Google's docs (drive api) for partial responses.


**Format**

Use `Swagger <http://swagger.io/specification/>`_ to generate API documentation where possible.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of our code seems to be using Django REST Swagger for Swagger documentation of DRF. Maybe this should be documented as our best practice, given that REST Framework Docs (which I think is documented below, was deprecated in favor of Django REST Swagger, both by the same creator. This is described on the DRF site for documenting APIs.

@efagin
Copy link
Contributor Author

efagin commented Jan 3, 2017

@andy-armstrong @robrap thanks for the early feedback! Many of your comments question the content itself. Since all I did was just port the existing wiki page over here, I'm surprised that there's so much in this document that you feel requires major editing. (This, on its own, is a good reason to move to OEP.)

Do you think we should broaden the scope of this OEP to actually go and revise these best practices? I had started this just figuring I'd do a quick port and merge, and then we could modify later, but if you think we should just do it all now, then I'll allocate more of my time to updating these best practices now.

@andy-armstrong
Copy link
Contributor

@efagin IMO it would be great if you could allocate the extra time to revise the recommendations. It seems like a good opportunity to make this up-to-date, and then we can all be on the same page going forward.

@efagin
Copy link
Contributor Author

efagin commented Jan 3, 2017

@andy-armstrong OK, I'll do that. This OEP will definitely require more effort before it's ready to merge, and please continue to provide feedback.

multiple PATCH styles in any given API, should this become desirable, without
breaking existing clients.

URL parameters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to describe how boolean query parameters should be handled. My preference is that they should be passed as true/false, but I'm open to other options.

I mention this because I dislike using 0/1 for boolean values, which I commented as such on this PR: https://github.com/edx/edx-platform/pull/14204

Documentation
-------------

Work with the Docs team to update the `edX platform API documentation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to revisit our documentation approach for APIs given the changes in the doc team. I'm not sure if this OEP is the best place to describe processes, but it would be good to lay out what is expected of documentation for a new API:

  • the API developer should use Swagger to auto-generate documentation (as mentioned below)
  • the developer is in charge of getting this documentation published (but how?)
  • how does an API get to be part of the API Gateway and have its documentation made available there too?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the link on this line is for edx-platform only, and is for a document that does not appear to be actively maintained. Also, this OEP needs to be for the community as a whole, so the language about "Work with the Docs team" doesn't generalize even if there were a docs team to work with.


The query parameters are as follows:

- ``page`` - the page of results (zero indexed)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why zero-indexed? I can't think of any of our own APIs that implement this. If we want to see this, and the other conventions (e.g. num_pages), implemented we should make it easy to do so by creating a pagination class in https://github.com/edx/edx-drf-extensions.


- ``page`` - the page of results (zero indexed)
- ``page_size`` - the number of results to return per page
- ``sort_order`` - a string indicating the desired order (no direction

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorting/ordering should be separate from pagination.

I would prefer we advocate ordering on explicit fields as it is clear to the client what is being done. Passing sort_order=asc is quite ambiguous.

e.g. https://courses.edx.org/api/user/v1/accounts/AndyA

See the `DRF documentation
<http://tomchristie.github.io/rest-framework-2-docs/topics/documenting-your-api>`_

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use DRF 3 everywhere. This is a more relevant URL: http://www.django-rest-framework.org/topics/documenting-your-api/


GET /api/enrollment/v1/enrollment/{user_id},{course_id}

**Response Values**

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not necessary when using Swagger. Also, docstrings like these tend to grow stale as APIs evolve since I don't necessarily have to touch a view to modify a serializer.


**Simple**

Keep the top-leveI resources clear and simple - focusing on what the client is
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo on "top-level"

**Prevent information leakage**

**Must**: Use 404 instead of 403 when the actual existence would be leaking
information that we don't want
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An example or two might be good here.

The query parameters are as follows:

- ``page`` - the page of results (zero indexed)
- ``page_size`` - the number of results to return per page
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Developers should explicitly set limits on this parameter.


We use the conventions established by `DRF
<http://www.django-rest-framework.org/api-guide/pagination/#pagenumberpagination>`_,
with some extra fields:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a note here about how certain very large collections (e.g. users, enrollments) cannot be effectively paged through with DRF's default pagination class? The choices then are to either use CursorPagination, a custom pagination class, or to simply cap the result set in some way:

  • "Returning the first 500 results that match your query."
  • "You have to be more specific before I give you any data."
  • "No, you may not crawl our entire enrollment database by making half a million sequential requests, please don't try that."

@efagin
Copy link
Contributor Author

efagin commented Jul 25, 2017

I know this has been idle for some time now. Part of the issue is the recurring theme that "best practice" OEPs are difficult to maintain and approve. For now, we've made the conscious decision at edX to keep Best Practice content in the wiki and allow freeform editing as practices evolve. Instead of leaving this open indefinitely, I'm going to withdraw this OEP, remove content, and merge the PR as-is. I will NOT squash commits unless this is desired - might be nice to have the commit history for archival purposes.

@andy-armstrong would you mind acting as Arbiter here?

Copy link
Contributor

@andy-armstrong andy-armstrong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 makes sense to me. As Arbiter, I'll go ahead and merge this now.

@andy-armstrong andy-armstrong merged commit 4929541 into master Jul 25, 2017
@andy-armstrong andy-armstrong deleted the efagin/oep-13-api-conventions branch July 25, 2017 20:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants