From 719799eca481dc75c90c4a061d6aadd196f93a48 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 5 Nov 2018 11:31:59 +0100 Subject: [PATCH 01/25] Initial idea about APIv3 --- docs/api/v3.rst | 320 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 docs/api/v3.rst diff --git a/docs/api/v3.rst b/docs/api/v3.rst new file mode 100644 index 00000000000..589133d791f --- /dev/null +++ b/docs/api/v3.rst @@ -0,0 +1,320 @@ +API v3 +====== + +The Read the Docs API uses :abbr:`REST (Representational State Transfer)`. +JSON is returned by all API responses including errors +and HTTP response status codes are to designate success and failure. + + +Authentication and authorization +-------------------------------- + +Requests to the Read the Docs public API are for public and private information +and do require authentication even for requesting public information. + +Scopes +~~~~~~ + +The API can be accessed by using the HTTP header ``Authorization`` +with a specific ``Token`` that provide access to different resources. + +Available scopes +++++++++++++++++ + +* ``project`` + * ``project:admin``: access to change admin settings (similar to Admin tab) + * ``project:read``: access to read all the information about the projects + * ``project:write``: access to anything related to perform write actions (triggering a Build for this project, activate/deactivate versions, etc) + * ``project:docs``: access any file from any version of the project's documentation + + +.. TODO: + + We could extend the scopes to be per-project or per-user. I'm not + sure if this is possible yet, but we should consider it. + + * per-project: the user could go to the Project Admin tab and create a Token for this specific project + * per-user: the user could go to their own User settings and create token for all his projects + + +Resources +--------- + +Projects +~~~~~~~~ + +Project list +++++++++++++ + +.. http:get:: /api/v3/project/ + + Retrieve a list of all the projects of the current logged in user. + + **Example request**: + + .. sourcecode:: bash + + $ curl https://readthedocs.org/api/v3/project/ + + **Example response**: + + .. sourcecode:: js + + { + "count": 25, + "next": "/api/v3/project/limit=10&offset=10", + "previous": null, + "results": [PROJECTS] + } + + :>json integer count: Total number of Projects. + :>json string next: URI for next set of Projects. + :>json string previous: URI for previous set of Projects. + :>json array results: Array of ``Project`` objects. + +.. TODO: + + Add query string filters to narrow the query: + * privacy level + * language + * programming language + * repo url + * repo type + * version active + * version built + * all database? + + +Project details ++++++++++++++++ + +.. http:get:: /api/v3/project/(string:slug)/ + + Retrieve details of a single project. + + .. sourcecode:: js + + { + "name": "Pip", + "slug": "pip", + "description": "Pip Installs Packages.", + "language": "en", + "programming_language": "py", + "repo": "https://github.com/pypa/pip", + "repo_type": "git", + "default_version": "stable", + "default_branch": "master", + "documentation_type": "sphinx_htmldir", + "canonical_url": "http://pip.pypa.io/en/stable/", + "links": [ + { + "href": "/api/v3/project/pip/users/", + "rel": "users", + "type": "GET" + }, + { + "href": "/api/v3/project/pip/versions/", + "rel": "versions", + "type": "GET" + }, + { + "href": "/api/v3/project/pip/builds/", + "rel": "builds", + "type": "GET" + }, + { + "href": "/api/v3/project/pip/domains/", + "rel": "domains", + "type": "GET" + }, + { + "href": "/api/v3/project/pip/notifications/", + "rel": "notifications", + "type": "GET" + }, + { + "href": "/api/v3/project/pip/features/", + "rel": "features", + "type": "GET" + }, + { + "href": "/api/v3/project/pip/subprojects/", + "rel": "subprojects", + "type": "GET" + }, + { + "href": "/api/v3/project/pip/translations/", + "rel": "translations", + "type": "GET" + } + ] + } + + + :>json string name: The name of the project. + :>json string slug: The project slug (used in the URL). + :>json string description: An RST description of the project + :>json string language: The language code of this project + :>json string programming_language: The programming language of the project (eg. "py", "js") + :>json string repo: The repository URL for the project + :>json string repo_type: Version control repository of the project + :>json string default_version: The default version of the project (eg. "latest", "stable", "v3") + :>json string default_branch: The default version control branch + :>json string documentation_type: An RST description of the project + :>json string canonical_url: The canonical URL of the default docs + :>json array links: Array with HEATEOAS_ links to retrieve related information + + :statuscode 200: Success + :statuscode 404: There is no ``Project`` with this slug + +.. TODO: + + Currently, v2 of this endpoint returns a lot of fields more like + ``enable_epub_build``, ``skip``, etc. + + https://readthedocs.org/api/v2/project/?slug=pip + + + +Versions +~~~~~~~~ + +Versions are different versions of the same project documentation. + +The versions for a given project can be viewed in a project's version screen. +For example, here is the `Pip project's version screen`_. + +.. _Pip project's version screen: https://readthedocs.org/projects/pip/versions/ + + +Version detail +++++++++++++++ + +.. http:get:: /api/v2/project/(string:project-slug)/versions/(string:version-slug)/ + + Retrieve details of a single version. + + .. sourcecode:: js + + { + "slug": "stable", + "verbose_name": "stable", + "identifier": "3a6b3995c141c0888af6591a59240ba5db7d9914", + "built": true, + "active": true, + "type": "tag", + "downloads": { + "pdf": "//readthedocs.org/projects/pip/downloads/pdf/stable/", + "htmlzip": "//readthedocs.org/projects/pip/downloads/htmlzip/stable/", + "epub": "//readthedocs.org/projects/pip/downloads/epub/stable/" + }, + "links": [ + { + "href": "/api/v3/project/pip/version/stable/builds/", + "rel": "builds", + "type": "GET" + }, + { + "href": "/api/v3/project/pip/", + "rel": "project", + "type": "GET" + } + ] + } + + :>json string slug: The version slug. + :>json string verbose_name: The name of the version. + :>json string identifier: A version control identifier for this version (eg. the commit hash of the tag) + :>json string built: Whether this version has been built + :>json string active: Whether this version is still active + :>json string type: The type of this version (typically "tag" or "branch") + :>json array downloads: URLs to downloads of this version's documentation + :>json array links: Array with HEATEOAS_ links to retrieve related information + + :statuscode 200: Success + :statuscode 404: There is no ``Version`` with this slug + + +Builds +~~~~~~ + +Builds are created by Read the Docs whenever a ``Project`` has its documentation built. +Frequently this happens automatically via a web hook but can be triggered manually. + +Builds can be viewed in the build screen for a project. +For example, here is `Pip's build screen`_. + +.. _Pip's build screen: https://readthedocs.org/projects/pip/builds/ + + +.. TODO: + + for filtering by ``commit`` we need the build listing --the other cases are useless + + +Build detail +++++++++++++ + +.. http:get:: /api/v3/build/(int:id)/ + + Retrieve details of a single build. + + .. sourcecode:: js + + { + "id": 7367364, + "date": "2018-06-19T15:15:59.135894", + "length": 59, + "type": "html", + "state": "finished", + "state_display": "Finished", + "success": true, + "error": null, + "commit": "6f808d743fd6f6907ad3e2e969c88a549e76db30", + "docs_url": "http://pip.pypa.io/en/latest/", + "builder": "build03", + "cold_storage": false, + "links": [ + { + "href": "/api/v3/build/7367364/commands/", + "rel": "commands", + "type": "GET" + }, + { + "href": "/api/v3/project/pip/", + "rel": "project", + "type": "GET" + }, + { + "href": "/api/v3/project/pip/version/latest/", + "rel": "version", + "type": "GET" + } + } + + + :>json integer id: The ID of the build + :>json string date: The ISO-8601 datetime of the build. + :>json integer length: The length of the build in seconds. + :>json string type: The type of the build (one of "html", "pdf", "epub") + :>json string state: The state of the build (one of "triggered", "building", "installing", "cloning", or "finished") + :>json string state_display: The state of the build to be shown to the user + :>json boolean success: Whether the build was successful + :>json string error: An error message if the build was unsuccessful + :>json string commit: A version control identifier for this build (eg. the commit hash) + :>json string docs_url: The canonical URL of the build docs + :>json string builder: The hostname server that built the docs + :>json array links: Array with HEATEOAS_ links to retrieve related information + + :statuscode 200: Success + :statuscode 404: There is no ``Build`` with this ID + + +References +---------- + +* https://www.django-rest-framework.org/topics/rest-hypermedia-hateoas/ +* https://blog.majsky.cz/implementing-hateoas-django-rest-framework/ +* https://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/#hyperlinking-our-api +* https://restfulapi.net/hateoas/ +* https://en.wikipedia.org/wiki/HATEOAS From 2bcff8b4b58686e3fd1d686fb8444df32a451c5e Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 5 Nov 2018 12:11:38 +0100 Subject: [PATCH 02/25] Endpoint in singular --- docs/api/v3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 589133d791f..eda1545f4f8 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -190,7 +190,7 @@ For example, here is the `Pip project's version screen`_. Version detail ++++++++++++++ -.. http:get:: /api/v2/project/(string:project-slug)/versions/(string:version-slug)/ +.. http:get:: /api/v2/project/(string:project-slug)/version/(string:version-slug)/ Retrieve details of a single version. From 3ace45bde7be24f05475d2b4bb1ed439d8b06b7d Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 5 Nov 2018 12:48:26 +0100 Subject: [PATCH 03/25] More endpoints --- docs/api/v3.rst | 174 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index eda1545f4f8..61143c05330 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -127,6 +127,11 @@ Project details "rel": "domains", "type": "GET" }, + { + "href": "/api/v3/project/pip/redirects/", + "rel": "redirects", + "type": "GET" + }, { "href": "/api/v3/project/pip/notifications/", "rel": "notifications", @@ -146,6 +151,11 @@ Project details "href": "/api/v3/project/pip/translations/", "rel": "translations", "type": "GET" + }, + { + "href": "/api/v3/project/pip/integrations/", + "rel": "translations", + "type": "GET" } ] } @@ -175,6 +185,115 @@ Project details https://readthedocs.org/api/v2/project/?slug=pip +Project import +++++++++++++++ + +.. http:post:: /api/v3/project/import/ + + Import a new project. + + **Example request**: + + .. sourcecode:: js + + // Simple form + { + "name": "Pip", + "repo_url": "https://github.com/pypa/pip", + "repo_type": "git" + } + + // Advanced form + { + "name": "Pip", + "repo_url": "https://github.com/pypa/pip", + "repo_type": "git" + "description": "Pip Installs Packages.", + "documentation_type": "sphinx_htmldir", + "language": "en", + "programing_language": "py", + "tags": [ + "pip", + "python", + "packaging" + ], + "homepage": "https://pip.readthedocs.io/" + } + + **Example response**: + + *See Project details* + + :statuscode 201: Created sucessfully + :statuscode 400: Some field is invalid + :statuscode 401: Not valid permissions + + +Project edit +++++++++++++ + +.. http:patch:: /api/v3/project/(string:slug)/ + + Edit a project. + + **Example request**: + + .. sourcecode:: js + + { + "description": "Pip helps you to install packages.", + "default_version": "stable", + "homepage": "https://pypi.org/project/pip/" + } + + :statuscode 204: Edited successfully + :statuscode 400: Some field is invalid + :statuscode 401: Not valid permissions + + +Add User to Project ++++++++++++++++++++ + + +.. http:post:: /api/v3/project/(string:slug)/users/ + + Add a User as mantainer to the project. + + **Example request**: + + .. sourcecode:: js + + { + "username": "humitos" + } + + :statuscode 201: Added successfully + :statuscode 400: Some field is invalid + :statuscode 401: Not valid permissions + + +Add Domain to Project ++++++++++++++++++++++ + + +.. http:post:: /api/v3/project/(string:slug)/domains/ + + Add a Domain to the project. + + **Example request**: + + .. sourcecode:: js + + { + "domain": "docs.pip.org" + "canonical": true, + "use_https": true + } + + :statuscode 201: Added successfully + :statuscode 400: Some field is invalid + :statuscode 401: Not valid permissions + Versions ~~~~~~~~ @@ -235,6 +354,32 @@ Version detail :statuscode 404: There is no ``Version`` with this slug +Version edit +++++++++++++ + +.. http:patch:: /api/v3/project/(string:slug)/version/(string:slug)/ + + Edit a version. + + **Example request**: + + .. sourcecode:: js + + { + "active": true, + "privacy_level": "public", + "tags": [ + "python", + "packaging" + ] + } + + :statuscode 204: Edited sucessfully + :statuscode 400: Some field is invalid + :statuscode 401: Not valid permissions + + + Builds ~~~~~~ @@ -310,6 +455,35 @@ Build detail :statuscode 404: There is no ``Build`` with this ID +Build triggering +++++++++++++++++ + +.. TODO: + + This endpoint may be under Project section + +.. http:post:: /api/v3/project/(string:slug)/builds/ + + Trigger a new build for this project. + + **Example request**: + + .. sourcecode:: js + + { + "version": "latest", + } + + **Example response**: + + *See Build details* + + :statuscode 201: Created sucessfully + :statuscode 400: Some field is invalid + :statuscode 401: Not valid permissions + + + References ---------- From c1f6b5f128fcaaef89c01f622cb72aa8fb4aaa6b Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 5 Nov 2018 13:58:49 +0100 Subject: [PATCH 04/25] Refactor --- docs/api/v3.rst | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 61143c05330..0682705e0a9 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -22,10 +22,10 @@ Available scopes ++++++++++++++++ * ``project`` - * ``project:admin``: access to change admin settings (similar to Admin tab) - * ``project:read``: access to read all the information about the projects - * ``project:write``: access to anything related to perform write actions (triggering a Build for this project, activate/deactivate versions, etc) - * ``project:docs``: access any file from any version of the project's documentation + * ``project:admin``: access to change admin settings (similar to Admin tab) + * ``project:read``: access to read all the information about the projects + * ``project:write``: access to anything related to perform write actions (triggering a Build for this project, activate/deactivate versions, etc) + * ``project:docs``: access any file from any version of the project's documentation .. TODO: @@ -196,14 +196,6 @@ Project import .. sourcecode:: js - // Simple form - { - "name": "Pip", - "repo_url": "https://github.com/pypa/pip", - "repo_type": "git" - } - - // Advanced form { "name": "Pip", "repo_url": "https://github.com/pypa/pip", @@ -220,6 +212,8 @@ Project import "homepage": "https://pip.readthedocs.io/" } + ``name``, ``repo_url`` and ``repo_type`` are required. + **Example response**: *See Project details* From de44330baf69142613f06b03a5713b1dd72c5262 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 5 Nov 2018 14:00:42 +0100 Subject: [PATCH 05/25] Typo for rendering --- docs/api/v3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 0682705e0a9..22321cb2bf3 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -303,7 +303,7 @@ For example, here is the `Pip project's version screen`_. Version detail ++++++++++++++ -.. http:get:: /api/v2/project/(string:project-slug)/version/(string:version-slug)/ +.. http:get:: /api/v2/project/(string:project_slug)/version/(string:version_slug)/ Retrieve details of a single version. From b3b00d7c7f9ede9da7c3539c200c96a20d392180 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 5 Nov 2018 14:02:02 +0100 Subject: [PATCH 06/25] Remove field --- docs/api/v3.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 22321cb2bf3..a2512e77ed2 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -404,7 +404,6 @@ Build detail "id": 7367364, "date": "2018-06-19T15:15:59.135894", "length": 59, - "type": "html", "state": "finished", "state_display": "Finished", "success": true, From b9775ddc3f7e72ad1fb093d80359df62f2fe7db6 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 5 Nov 2018 17:15:12 +0100 Subject: [PATCH 07/25] Footer endpoint --- docs/api/v3.rst | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index a2512e77ed2..c181b3aec54 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -476,6 +476,76 @@ Build triggering :statuscode 401: Not valid permissions +Footer +~~~~~~ + + +.. http:get:: /api/v3/footer/(string:project_slug)/ + + Retrieve footer data for the project. + + **Example response**: + + .. sourcecode:: js + + { + "version": {VERSION DETAIL}, + "project": {PROJECT DETAIL}, + "sphinx": { + "html_theme": "sphinx_rtd_theme", + "source_suffix": ".rst" + }, + "analytics": { + "user_analytics_code": "UA-00000", + "global_analytics_code": "UA-00001" + }, + "vcs": { + "type": "github" + "user": "pypa", + "repo": "pip", + "commit": "3a6b3995c141c0888af6591a59240ba5db7d9914", + "version": "18.1", + "display": true, + "conf_py_path": "/docs/conf.py" + }, + "meta": { + "API_HOST": "readthedocs.org", + "MEDIA_URL": "https://media.readthedocs.org", + "PRODUCTION_DOMAIN": "readthedocs.io", + "READTHEDOCS": true + } + } + } + + + .. TODO: + + Complete JSON body response fields + + :query string version_slug: The version slug of the current docs + :query string page_slug: Page currently displayed to user for reading + :query string theme: Theme used in the documentation + :query string docroot: Docroot used to generate external links + :query string source_suffix: Source suffix used to generate external links + :query string format: Output format (``jsonp``, ``json``) + + :statuscode 200: Success + :statuscode 404: There is no ``Project`` with this slug + + + .. TODO: + + We could return less information here and rely on the client to + query what is specifically needed to create the footer version + flyout but we will probably do all the queries in the general + case. I think it's preferable to return what is needed in this + case and if less information is required, other endpoints can + be used. + + The name of the endpoint could be under + ``/api/v3/project/(string:slug)/flyout/`` maybe or similar + since it's not a footer I think. + References ---------- @@ -485,3 +555,4 @@ References * https://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/#hyperlinking-our-api * https://restfulapi.net/hateoas/ * https://en.wikipedia.org/wiki/HATEOAS +* https://martinfowler.com/articles/richardsonMaturityModel.html#level3 From 4c0cee115fff1091c9242c2024244aa5cdedbc6f Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 6 Nov 2018 13:31:15 +0100 Subject: [PATCH 08/25] Design document for APIv3 to discuss --- docs/design/apiv3.rst | 209 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 docs/design/apiv3.rst diff --git a/docs/design/apiv3.rst b/docs/design/apiv3.rst new file mode 100644 index 00000000000..8d1402b9d77 --- /dev/null +++ b/docs/design/apiv3.rst @@ -0,0 +1,209 @@ +Design of APIv3 +=============== + +APIv3 will be designed to be easy to use and useful to perform read and write operations as the main two goals. + +It will be based on Resources as APIv2 but considering the ``Project`` resource as the main one, +from where most of the endpoint will be based on it. + + +Problems with APIv2 +------------------- + + +* No authentication +* It's read-only +* Not designed for slugs +* Useful APIs not exposed (only for internal usage currently) +* Error reporting is a mess +* Relationships between API resources is not obvious +* Footer API endpoint returns HTML + + +Proposed improves ++++++++++++++++++ + + +Use authentication +~~~~~~~~~~~~~~~~~~ + +* Pros: + + * queries can be personalized depending on the user + * allows us to perform write actions + +* Cons: + + * harder to implement + * requires a lot of time for good testing and QA + + +Questions: + +#. Do we want make auth a requirement? +#. Should we expose some endpoints as Read Only if not authenticated? +#. How we do communicate users about deprecation if they are Anonymous? Is it enough to add a note in the docs saying that "Auth is preferred for communication"? +#. How are we going to expose the ``Token`` required for Auth when building if auth is mandatory? + + +Read and Write +~~~~~~~~~~~~~~ + +* Pros: + + * most of the actions can be performed by a script instead of by + accessing readthedocs.org with a browser + +* Cons: + + * we have to deal with authorization + * open the door to possibilities of security holes + + +Questions: + +#. Do we want to allow the user to perform **all the write actions** + that are possible to do from the dashboard via the API? + + +Design it for slugs +~~~~~~~~~~~~~~~~~~~ + +* Pros: + + * knowing the slug of your project (which is presented to the user) + you can perform all the actions or retrieve all the data + +* Cons: + + * it will be a mixture between most of the endpoint using ``slug`` + and to retrieve details of a Build it will be an ``id`` + + +Expose internal endpoints +~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are some endpoints that we are using internally like +``/api/v2/search/``, ``/api/v2/footer/`` and +``/api/v2/sustainability/``. + + +* Pros: + + * allow to build custom footer + * allow to build custom search autocomplete widget + +* Cons: + + * n/a + +Questions: + +#. Do we want to add ``/api/v2/sustainability/`` to APIv3 or that + should be part of the new Ad Server that we are building? + + +Proper status codes for error reporting +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Pros: + + * user knows what it's happening and can take decisions about it + +* Cons: + + * n/a + + +Relationship between API resources +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Pros: + + * browse-able API by accessing to the default resource (Project) + * knowing the project's slug you can perform all the actions related to it + +* Cons: + + * more data is returned with all the links to the endpoints + + +Make footer API returns JSON +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Pros: + + * users can build their own version menu flyout + * cleaner than returning a HTML and injecting it + +* Cons: + + * we need to adapt our theme for this + + +Questions: + +#. Do we want an specific endpoint for the footer? +#. The flyout could be built by querying 2 or 3 of the regular + endpoint. Would this add too much overhead to the page loading + time? + + +Use cases +--------- + +We want to cover +++++++++++++++++ + + +* Return all **my** projects +* Access all the resources by knowing the project's slug +* Ability to filter by fields + + * all the active versions of specific project + +* Data about builds + + * latest build for project + * latest build for a particular version of a project + * status of a particular build + +* Perform write actions like + + * add a Domain, + * add User as mantainer, + * import a new Project under my username, + * set the language of the Project, + * trigger a Build, + * activate/deactivate a Version to be built, + * and all the actions you can perform from the Admin tab. + +* Retrieve all the information needed to create a custom version menu flyout + + +Considering some useful cases for the corporate site: + +* Give access to a doc page (``objects.inv``, ``/design/core.html``) + + +We do NOT want to cover ++++++++++++++++++++++++ + +* Random filtering over a whole and not useful Resource + + * "All the ``stable`` versions" + * "Builds with ``exit_code`` equal to 257" + + +Technical aspects that would be good to have +-------------------------------------------- + +* Rate limit +* ``Request-ID`` header +* `JSON minified by default`_ (maybe with ``?pretty=true``) +* `JSON schema and validation`_ with docs_ + + +.. _JSON minified by default: https://geemus.gitbooks.io/http-api-design/content/en/responses/keep-json-minified-in-all-responses.html +.. _JSON schema and validation: https://geemus.gitbooks.io/http-api-design/content/en/responses/keep-json-minified-in-all-responses.html +.. _docs: https://geemus.gitbooks.io/http-api-design/content/en/artifacts/provide-human-readable-docs.html From 87c67c3b4859172d4ae9cb3a0ed00a98861a5b0b Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 18 Feb 2019 19:02:35 +0100 Subject: [PATCH 09/25] Update common submodule --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index f3c2619adb1..ac9eafa1e57 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit f3c2619adb171d1cbfae9c28922dddc46cd98cd1 +Subproject commit ac9eafa1e57c5ab3cff5af9acad1e93c85989e8c From e637bdb02f8aaaaa5cf0bc4c47758394e0acc961 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 19 Feb 2019 15:35:44 +0100 Subject: [PATCH 10/25] Rework after core team decisions --- docs/api/v3.rst | 473 ++++++++++++++++-------------------------------- 1 file changed, 154 insertions(+), 319 deletions(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index c181b3aec54..df04a9400a5 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -5,37 +5,35 @@ The Read the Docs API uses :abbr:`REST (Representational State Transfer)`. JSON is returned by all API responses including errors and HTTP response status codes are to designate success and failure. +.. warning:: + + APIv3 is currently under development and it's not ready to use yet. + Authentication and authorization -------------------------------- Requests to the Read the Docs public API are for public and private information -and do require authentication even for requesting public information. +and do require authentication for all listing endpoints but not for all detailed ones. -Scopes -~~~~~~ +No authentication +~~~~~~~~~~~~~~~~~ -The API can be accessed by using the HTTP header ``Authorization`` -with a specific ``Token`` that provide access to different resources. +Some endpoints on read-only requests won't require any kind of authentication. +Most of them are detailed information for a particular object. -Available scopes -++++++++++++++++ +Token +~~~~~ -* ``project`` - * ``project:admin``: access to change admin settings (similar to Admin tab) - * ``project:read``: access to read all the information about the projects - * ``project:write``: access to anything related to perform write actions (triggering a Build for this project, activate/deactivate versions, etc) - * ``project:docs``: access any file from any version of the project's documentation +All listing endpoints or those that perform non-readonly operations, +require authentication by using the HTTP header ``Authorization`` +with a specific ``Token`` that provide full access identified as an user. -.. TODO: - - We could extend the scopes to be per-project or per-user. I'm not - sure if this is possible yet, but we should consider it. - - * per-project: the user could go to the Project Admin tab and create a Token for this specific project - * per-user: the user could go to their own User settings and create token for all his projects +Session +~~~~~~~ +.. TODO: Resources --------- @@ -43,18 +41,18 @@ Resources Projects ~~~~~~~~ -Project list -++++++++++++ +Projects list ++++++++++++++ -.. http:get:: /api/v3/project/ +.. http:get:: /api/v3/projects/ - Retrieve a list of all the projects of the current logged in user. + Retrieve a list of all the projects for the current logged in user. **Example request**: .. sourcecode:: bash - $ curl https://readthedocs.org/api/v3/project/ + $ curl -H "Authorization: Token " https://readthedocs.org/api/v3/projects/ **Example response**: @@ -62,9 +60,9 @@ Project list { "count": 25, - "next": "/api/v3/project/limit=10&offset=10", + "next": "/api/v3/projects/limit=10&offset=10", "previous": null, - "results": [PROJECTS] + "results": [PROJECT] } :>json integer count: Total number of Projects. @@ -88,7 +86,7 @@ Project list Project details +++++++++++++++ -.. http:get:: /api/v3/project/(string:slug)/ +.. http:get:: /api/v3/projects/(string:project_slug)/ Retrieve details of a single project. @@ -98,195 +96,79 @@ Project details "name": "Pip", "slug": "pip", "description": "Pip Installs Packages.", - "language": "en", - "programming_language": "py", - "repo": "https://github.com/pypa/pip", - "repo_type": "git", + "created": "2010-10-23T18:12:31+00:00", + "modified": "2018-12-11T07:21:11+00:00", + "language": { + "code": "en", + "name": "English" + }, + "programming_language": { + "code": "py", + "name": "Python" + } + "repository": { + "url": "https://github.com/pypa/pip", + "type": "git" + }, "default_version": "stable", "default_branch": "master", "documentation_type": "sphinx_htmldir", - "canonical_url": "http://pip.pypa.io/en/stable/", - "links": [ - { - "href": "/api/v3/project/pip/users/", - "rel": "users", - "type": "GET" - }, - { - "href": "/api/v3/project/pip/versions/", - "rel": "versions", - "type": "GET" - }, - { - "href": "/api/v3/project/pip/builds/", - "rel": "builds", - "type": "GET" - }, - { - "href": "/api/v3/project/pip/domains/", - "rel": "domains", - "type": "GET" - }, - { - "href": "/api/v3/project/pip/redirects/", - "rel": "redirects", - "type": "GET" - }, - { - "href": "/api/v3/project/pip/notifications/", - "rel": "notifications", - "type": "GET" - }, - { - "href": "/api/v3/project/pip/features/", - "rel": "features", - "type": "GET" - }, - { - "href": "/api/v3/project/pip/subprojects/", - "rel": "subprojects", - "type": "GET" - }, - { - "href": "/api/v3/project/pip/translations/", - "rel": "translations", - "type": "GET" - }, - { - "href": "/api/v3/project/pip/integrations/", - "rel": "translations", - "type": "GET" - } + "privacy_level": "public", + "urls": { + "documentation": "http://pip.pypa.io/en/stable/", + "project": "https://pip.pypa.io/" + } + "last_build": {BUILD}, + "tags": [ + "disutils", + "easy_install", + "egg", + "setuptools", + "virtualenv" + ], + "maintainers": [ + "/api/v3/users//", + ], + "versions": [ + "/api/v3/projects/pip/versions/stable/" + "/api/v3/projects/pip/versions/latest/", + "/api/v3/projects/pip/versions/19.0.2/", + ], + "subprojects": [ + "/api/v3/projects/pip-subproject/" + ], + "translations": [ + "/api/v3/projects/pip-es/" ] } + .. TODO: by default it should return *only active versions*, and + having the posibility to return ``?versions__active=False`` or + something like that. Otherwise, including all the versions by + default will generate ton of data probably. + :>json string name: The name of the project. :>json string slug: The project slug (used in the URL). :>json string description: An RST description of the project - :>json string language: The language code of this project - :>json string programming_language: The programming language of the project (eg. "py", "js") - :>json string repo: The repository URL for the project - :>json string repo_type: Version control repository of the project - :>json string default_version: The default version of the project (eg. "latest", "stable", "v3") - :>json string default_branch: The default version control branch - :>json string documentation_type: An RST description of the project - :>json string canonical_url: The canonical URL of the default docs - :>json array links: Array with HEATEOAS_ links to retrieve related information + + .. TODO: complete the returned data docs once agreed on this. :statuscode 200: Success :statuscode 404: There is no ``Project`` with this slug -.. TODO: - - Currently, v2 of this endpoint returns a lot of fields more like - ``enable_epub_build``, ``skip``, etc. - - https://readthedocs.org/api/v2/project/?slug=pip - - -Project import -++++++++++++++ - -.. http:post:: /api/v3/project/import/ - - Import a new project. - - **Example request**: - - .. sourcecode:: js - - { - "name": "Pip", - "repo_url": "https://github.com/pypa/pip", - "repo_type": "git" - "description": "Pip Installs Packages.", - "documentation_type": "sphinx_htmldir", - "language": "en", - "programing_language": "py", - "tags": [ - "pip", - "python", - "packaging" - ], - "homepage": "https://pip.readthedocs.io/" - } - - ``name``, ``repo_url`` and ``repo_type`` are required. - - **Example response**: - - *See Project details* - - :statuscode 201: Created sucessfully - :statuscode 400: Some field is invalid - :statuscode 401: Not valid permissions - - -Project edit -++++++++++++ - -.. http:patch:: /api/v3/project/(string:slug)/ - - Edit a project. - - **Example request**: - - .. sourcecode:: js - - { - "description": "Pip helps you to install packages.", - "default_version": "stable", - "homepage": "https://pypi.org/project/pip/" - } - - :statuscode 204: Edited successfully - :statuscode 400: Some field is invalid - :statuscode 401: Not valid permissions +.. note:: -Add User to Project -+++++++++++++++++++ + This endpoint can be accessed anonymously. -.. http:post:: /api/v3/project/(string:slug)/users/ - - Add a User as mantainer to the project. - - **Example request**: - - .. sourcecode:: js - - { - "username": "humitos" - } - - :statuscode 201: Added successfully - :statuscode 400: Some field is invalid - :statuscode 401: Not valid permissions - - -Add Domain to Project -+++++++++++++++++++++ - - -.. http:post:: /api/v3/project/(string:slug)/domains/ - - Add a Domain to the project. - - **Example request**: - - .. sourcecode:: js +.. TODO: - { - "domain": "docs.pip.org" - "canonical": true, - "use_https": true - } + Currently, v2 of this endpoint returns a lot of fields more like + ``enable_epub_build``, ``skip``, etc. - :statuscode 201: Added successfully - :statuscode 400: Some field is invalid - :statuscode 401: Not valid permissions + https://readthedocs.org/api/v2/project/?slug=pip Versions @@ -294,16 +176,16 @@ Versions Versions are different versions of the same project documentation. -The versions for a given project can be viewed in a project's version screen. -For example, here is the `Pip project's version screen`_. +The versions for a given project can be viewed in a project's version page. +For example, here is the `Pip project's version page`_. -.. _Pip project's version screen: https://readthedocs.org/projects/pip/versions/ +.. _Pip project's version page: https://readthedocs.org/projects/pip/versions/ Version detail ++++++++++++++ -.. http:get:: /api/v2/project/(string:project_slug)/version/(string:version_slug)/ +.. http:get:: /api/v3/projects/(string:project_slug)/version/(string:version_slug)/ Retrieve details of a single version. @@ -316,42 +198,31 @@ Version detail "built": true, "active": true, "type": "tag", + "last_build": {BUILD}, "downloads": { "pdf": "//readthedocs.org/projects/pip/downloads/pdf/stable/", "htmlzip": "//readthedocs.org/projects/pip/downloads/htmlzip/stable/", "epub": "//readthedocs.org/projects/pip/downloads/epub/stable/" - }, - "links": [ - { - "href": "/api/v3/project/pip/version/stable/builds/", - "rel": "builds", - "type": "GET" - }, - { - "href": "/api/v3/project/pip/", - "rel": "project", - "type": "GET" - } - ] + } } - :>json string slug: The version slug. - :>json string verbose_name: The name of the version. + :>json string slug: The slug for this version + :>json string verbose_name: The name of the version :>json string identifier: A version control identifier for this version (eg. the commit hash of the tag) :>json string built: Whether this version has been built - :>json string active: Whether this version is still active + :>json string active: Whether this version is active :>json string type: The type of this version (typically "tag" or "branch") + :>json string last_build: Build object representing the last build of this version :>json array downloads: URLs to downloads of this version's documentation - :>json array links: Array with HEATEOAS_ links to retrieve related information :statuscode 200: Success - :statuscode 404: There is no ``Version`` with this slug + :statuscode 404: There is no ``Version`` with this slug for this project Version edit ++++++++++++ -.. http:patch:: /api/v3/project/(string:slug)/version/(string:slug)/ +.. http:patch:: /api/v3/projects/(string:project_slug)/version/(string:version_slug)/ Edit a version. @@ -371,7 +242,7 @@ Version edit :statuscode 204: Edited sucessfully :statuscode 400: Some field is invalid :statuscode 401: Not valid permissions - + :statuscode 404: There is no ``Version`` with this slug for this project Builds @@ -380,10 +251,10 @@ Builds Builds are created by Read the Docs whenever a ``Project`` has its documentation built. Frequently this happens automatically via a web hook but can be triggered manually. -Builds can be viewed in the build screen for a project. -For example, here is `Pip's build screen`_. +Builds can be viewed in the build page for a project. +For example, here is `Pip's build page`_. -.. _Pip's build screen: https://readthedocs.org/projects/pip/builds/ +.. _Pip's build page: https://readthedocs.org/projects/pip/builds/ .. TODO: @@ -394,7 +265,11 @@ For example, here is `Pip's build screen`_. Build detail ++++++++++++ -.. http:get:: /api/v3/build/(int:id)/ +There are two different ways to access to a specific build. +One is by accessing with the ``id`` of the build object. +The other way is by accessing by using the commit hash. + +.. http:get:: /api/v3/builds/(int:build_id)/ Retrieve details of a single build. @@ -402,60 +277,60 @@ Build detail { "id": 7367364, - "date": "2018-06-19T15:15:59.135894", - "length": 59, - "state": "finished", - "state_display": "Finished", + "version": "latest", + "project": "pip", + "created": "2018-06-19T15:15:59+00:00", + "finished": "2018-06-19T15:16:58+00:00", + "duration": 59, + "state": { + "code": "finished", + "name": "Finished" + }, "success": true, "error": null, "commit": "6f808d743fd6f6907ad3e2e969c88a549e76db30", - "docs_url": "http://pip.pypa.io/en/latest/", "builder": "build03", "cold_storage": false, - "links": [ - { - "href": "/api/v3/build/7367364/commands/", - "rel": "commands", - "type": "GET" - }, - { - "href": "/api/v3/project/pip/", - "rel": "project", - "type": "GET" - }, - { - "href": "/api/v3/project/pip/version/latest/", - "rel": "version", - "type": "GET" - } + "commands": [ + "/api/v3/buildcommands/7281720376/", + "/api/v3/buildcommands/7281720377/", + ], } :>json integer id: The ID of the build :>json string date: The ISO-8601 datetime of the build. - :>json integer length: The length of the build in seconds. - :>json string type: The type of the build (one of "html", "pdf", "epub") + :>json integer duration: The length of the build in seconds. :>json string state: The state of the build (one of "triggered", "building", "installing", "cloning", or "finished") - :>json string state_display: The state of the build to be shown to the user :>json boolean success: Whether the build was successful :>json string error: An error message if the build was unsuccessful :>json string commit: A version control identifier for this build (eg. the commit hash) - :>json string docs_url: The canonical URL of the build docs :>json string builder: The hostname server that built the docs - :>json array links: Array with HEATEOAS_ links to retrieve related information + :>json string cold_storage: Whether the build was removed from database and stored externally :statuscode 200: Success :statuscode 404: There is no ``Build`` with this ID +.. http:get:: /api/v3/projects/(str:project_slug)/builds/(str:commit_hash)/ + + Retrieve details for all the builds matching the commit hash on this project. + + .. sourcecode:: js + + { + "count": 15, + "next": "/api/v3/projects/pip/builds/24f652b/?limit=10&offset=10", + "previous": null, + "results": [BUILD] + } + + Build triggering ++++++++++++++++ -.. TODO: - - This endpoint may be under Project section -.. http:post:: /api/v3/project/(string:slug)/builds/ +.. http:post:: /api/v3/projects/(string:project_slug)/builds/ Trigger a new build for this project. @@ -476,83 +351,43 @@ Build triggering :statuscode 401: Not valid permissions -Footer -~~~~~~ - +Build commands listing +++++++++++++++++++++++ -.. http:get:: /api/v3/footer/(string:project_slug)/ +.. http:get:: /api/v3/builds/(int:build_id)/commands/ - Retrieve footer data for the project. - - **Example response**: + Retrieve build command list of a single build. .. sourcecode:: js { - "version": {VERSION DETAIL}, - "project": {PROJECT DETAIL}, - "sphinx": { - "html_theme": "sphinx_rtd_theme", - "source_suffix": ".rst" - }, - "analytics": { - "user_analytics_code": "UA-00000", - "global_analytics_code": "UA-00001" - }, - "vcs": { - "type": "github" - "user": "pypa", - "repo": "pip", - "commit": "3a6b3995c141c0888af6591a59240ba5db7d9914", - "version": "18.1", - "display": true, - "conf_py_path": "/docs/conf.py" - }, - "meta": { - "API_HOST": "readthedocs.org", - "MEDIA_URL": "https://media.readthedocs.org", - "PRODUCTION_DOMAIN": "readthedocs.io", - "READTHEDOCS": true - } + "count": 15, + "next": "/api/v3/builds/719263915/commands/?limit=10&offset=10", + "previous": null, + "results": [BUILDCOMMAND] } - } - .. TODO: - - Complete JSON body response fields - - :query string version_slug: The version slug of the current docs - :query string page_slug: Page currently displayed to user for reading - :query string theme: Theme used in the documentation - :query string docroot: Docroot used to generate external links - :query string source_suffix: Source suffix used to generate external links - :query string format: Output format (``jsonp``, ``json``) - - :statuscode 200: Success - :statuscode 404: There is no ``Project`` with this slug - + :>json integer id: The ID of the build + :>json string date: The ISO-8601 datetime of the build. + :>json integer duration: The length of the build in seconds. - .. TODO: - We could return less information here and rely on the client to - query what is specifically needed to create the footer version - flyout but we will probably do all the queries in the general - case. I think it's preferable to return what is needed in this - case and if less information is required, other endpoints can - be used. +Build command details ++++++++++++++++++++++ - The name of the endpoint could be under - ``/api/v3/project/(string:slug)/flyout/`` maybe or similar - since it's not a footer I think. +.. http:get:: /api/v3/buildcommands/(int:buildcommand_id)/ + Retrieve build command detail. -References ----------- + .. sourcecode:: js -* https://www.django-rest-framework.org/topics/rest-hypermedia-hateoas/ -* https://blog.majsky.cz/implementing-hateoas-django-rest-framework/ -* https://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/#hyperlinking-our-api -* https://restfulapi.net/hateoas/ -* https://en.wikipedia.org/wiki/HATEOAS -* https://martinfowler.com/articles/richardsonMaturityModel.html#level3 + { + "build": 719263915, + "created": "2018-06-19T15:15:59+00:00", + "finished": "2018-06-19T15:16:58+00:00", + "duration": 59, + "command": "cat docs/config.py", + "output": "...", + "exit_code": 0 + } From ca091c67c06157acd2789c9dffdaa0c7a71040cd Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 19 Feb 2019 16:33:48 +0100 Subject: [PATCH 11/25] Request examples and required headers --- docs/api/v3.rst | 197 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 152 insertions(+), 45 deletions(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index df04a9400a5..3ef84d5f94f 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -13,27 +13,33 @@ and HTTP response status codes are to designate success and failure. Authentication and authorization -------------------------------- -Requests to the Read the Docs public API are for public and private information -and do require authentication for all listing endpoints but not for all detailed ones. +Requests to the Read the Docs public API are for public and private information. +Some listing endpoints and some detailed ones are allowed to access without being authenticated. +Although, all endpoints that perform non-readonly operations, require authentication. + No authentication ~~~~~~~~~~~~~~~~~ Some endpoints on read-only requests won't require any kind of authentication. -Most of them are detailed information for a particular object. +Most of them are detailed information of specific listings for a particular object. + Token ~~~~~ -All listing endpoints or those that perform non-readonly operations, -require authentication by using the HTTP header ``Authorization`` -with a specific ``Token`` that provide full access identified as an user. +The ``Authorization`` HTTP header can be specified with a ``Token`` to authenticate as a user +and have the same permissions that the user itself. Session ~~~~~~~ -.. TODO: +Session authentication is allowed on very specific endpoints, +to allow hitting the API when reading documentation. + +When a user is trying to authenticate via session, CSRF check is performed. + Resources --------- @@ -70,17 +76,22 @@ Projects list :>json string previous: URI for previous set of Projects. :>json array results: Array of ``Project`` objects. -.. TODO: + :query privacy_level: one of ``public``, ``private``, ``protected`` + + .. TODO: + + Add query string filters to narrow the query: + * privacy level + * language + * programming language + * repository url + * repository type + * all fields? + + Considering that we are listing only projects associated with the authenticated user, + we should not have performance problem with these filters - Add query string filters to narrow the query: - * privacy level - * language - * programming language - * repo url - * repo type - * version active - * version built - * all database? + :reqheader Authorization: required token to authenticate Project details @@ -90,6 +101,15 @@ Project details Retrieve details of a single project. + **Example request**: + + .. sourcecode:: bash + + $ curl https://readthedocs.org/api/v3/projects/pip/ + + **Example response**: + + .. sourcecode:: js { @@ -126,13 +146,16 @@ Project details "setuptools", "virtualenv" ], - "maintainers": [ - "/api/v3/users//", + "users": [ + "/api/v3/users/dstufft/", + "/api/v3/users/pmoore/", + "/api/v3/users/xafer/", + "/api/v3/users/pradyunsg/" ], "versions": [ - "/api/v3/projects/pip/versions/stable/" + "/api/v3/projects/pip/versions/stable/", "/api/v3/projects/pip/versions/latest/", - "/api/v3/projects/pip/versions/19.0.2/", + "/api/v3/projects/pip/versions/19.0.2/" ], "subprojects": [ "/api/v3/projects/pip-subproject/" @@ -143,9 +166,9 @@ Project details } .. TODO: by default it should return *only active versions*, and - having the posibility to return ``?versions__active=False`` or + having the possibility to return ``?only_active_versions=False`` or something like that. Otherwise, including all the versions by - default will generate ton of data probably. + default will generate ton of data for some projects probably. :>json string name: The name of the project. @@ -154,22 +177,12 @@ Project details .. TODO: complete the returned data docs once agreed on this. + :reqheader Authorization: optional token to authenticate + :statuscode 200: Success :statuscode 404: There is no ``Project`` with this slug -.. note:: - - This endpoint can be accessed anonymously. - - -.. TODO: - - Currently, v2 of this endpoint returns a lot of fields more like - ``enable_epub_build``, ``skip``, etc. - - https://readthedocs.org/api/v2/project/?slug=pip - Versions ~~~~~~~~ @@ -189,6 +202,14 @@ Version detail Retrieve details of a single version. + **Example request**: + + .. sourcecode:: bash + + $ curl https://readthedocs.org/api/v3/projects/pip/versions/latest/ + + **Example response**: + .. sourcecode:: js { @@ -215,6 +236,8 @@ Version detail :>json string last_build: Build object representing the last build of this version :>json array downloads: URLs to downloads of this version's documentation + :reqheader Authorization: optional token to authenticate + :statuscode 200: Success :statuscode 404: There is no ``Version`` with this slug for this project @@ -239,6 +262,12 @@ Version edit ] } + **Example response**: + + *See Version details* + + :reqheader Authorization: required token to authenticate + :statuscode 204: Edited sucessfully :statuscode 400: Some field is invalid :statuscode 401: Not valid permissions @@ -257,26 +286,25 @@ For example, here is `Pip's build page`_. .. _Pip's build page: https://readthedocs.org/projects/pip/builds/ -.. TODO: +Build details ++++++++++++++ - for filtering by ``commit`` we need the build listing --the other cases are useless +.. http:get:: /api/v3/builds/(int:build_id)/ + Retrieve details of a single build. -Build detail -++++++++++++ + **Example request**: -There are two different ways to access to a specific build. -One is by accessing with the ``id`` of the build object. -The other way is by accessing by using the commit hash. + .. sourcecode:: bash -.. http:get:: /api/v3/builds/(int:build_id)/ + $ curl https://readthedocs.org/api/v3/builds/8592686/ - Retrieve details of a single build. + **Example response**: .. sourcecode:: js { - "id": 7367364, + "id": 8592686, "version": "latest", "project": "pip", "created": "2018-06-19T15:15:59+00:00", @@ -308,14 +336,44 @@ The other way is by accessing by using the commit hash. :>json string builder: The hostname server that built the docs :>json string cold_storage: Whether the build was removed from database and stored externally + :reqheader Authorization: optional token to authenticate + :statuscode 200: Success :statuscode 404: There is no ``Build`` with this ID +.. http:get:: /api/v3/projects/(str:project_slug)/builds/latest/ + + Retrieve details for latest build on this project. + + **Example request**: + + .. sourcecode:: bash + + $ curl https://readthedocs.org/api/v3/projects/pip/builds/latest/ + + **Example response**: + + *See Build details* + + :reqheader Authorization: optional token to authenticate + + +Builds listing +++++++++++++++ + .. http:get:: /api/v3/projects/(str:project_slug)/builds/(str:commit_hash)/ Retrieve details for all the builds matching the commit hash on this project. + **Example request**: + + .. sourcecode:: bash + + $ curl https://readthedocs.org/api/v3/projects/pip/builds/24f652b/ + + **Example response**: + .. sourcecode:: js { @@ -325,6 +383,32 @@ The other way is by accessing by using the commit hash. "results": [BUILD] } + :reqheader Authorization: optional token to authenticate + + +.. http:get:: /api/v3/projects/(str:project_slug)/builds/running/ + + Retrieve details for all the builds that are currently building for this project. + + **Example request**: + + .. sourcecode:: bash + + $ curl https://readthedocs.org/api/v3/projects/pip/builds/running/ +. + **Example response**: + + .. sourcecode:: js + + { + "count": 15, + "next": "/api/v3/projects/pip/builds/running/?limit=10&offset=10", + "previous": null, + "results": [BUILD] + } + + :reqheader Authorization: optional token to authenticate + Build triggering ++++++++++++++++ @@ -346,6 +430,8 @@ Build triggering *See Build details* + :reqheader Authorization: required token to authenticate + :statuscode 201: Created sucessfully :statuscode 400: Some field is invalid :statuscode 401: Not valid permissions @@ -358,6 +444,14 @@ Build commands listing Retrieve build command list of a single build. + **Example request**: + + .. sourcecode:: bash + + $ curl https://readthedocs.org/api/v3/builds/719263915/commands/ +. + **Example response**: + .. sourcecode:: js { @@ -372,6 +466,8 @@ Build commands listing :>json string date: The ISO-8601 datetime of the build. :>json integer duration: The length of the build in seconds. + :reqheader Authorization: optional token to authenticate + Build command details +++++++++++++++++++++ @@ -380,9 +476,18 @@ Build command details Retrieve build command detail. + **Example request**: + + .. sourcecode:: bash + + $ curl https://readthedocs.org/api/v3/buildcommands/9182639172/ +. + **Example response**: + .. sourcecode:: js { + "id": 9182639172, "build": 719263915, "created": "2018-06-19T15:15:59+00:00", "finished": "2018-06-19T15:16:58+00:00", @@ -391,3 +496,5 @@ Build command details "output": "...", "exit_code": 0 } + + :reqheader Authorization: optional token to authenticate From 92a93453a2ee979ad0376b800576122bcc8b61b8 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 19 Feb 2019 16:39:18 +0100 Subject: [PATCH 12/25] Version listing endpoint --- docs/api/v3.rst | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 3ef84d5f94f..9eb9446eadf 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -195,6 +195,46 @@ For example, here is the `Pip project's version page`_. .. _Pip project's version page: https://readthedocs.org/projects/pip/versions/ +Versions listing +++++++++++++++++ + +.. http:get:: /api/v3/projects/(string:project_slug)/versions/ + + Retrieve a list of all versions for a project. + + **Example request**: + + .. sourcecode:: bash + + $ curl https://readthedocs.org/api/v3/projects/pip/versions/ + + **Example response**: + + .. sourcecode:: js + + { + "count": 25, + "next": "/api/v3/projects/pip/versions/?limit=10&offset=10", + "previous": null, + "results": [VERSION] + } + + :>json integer count: Total number of Projects. + :>json string next: URI for next set of Projects. + :>json string previous: URI for previous set of Projects. + :>json array results: Array of ``Version`` objects. + + .. TODO: instead of an array, this could potentially be a + dictionary with the slug as the key and a VERSION as value. + + :query limit: limit number of object returned + :query offset: offset from the whole list returned + :query active: one of ``true``, ``false`` + :query built: one of ``true``, ``false`` + + :reqheader Authorization: optional token to authenticate + + Version detail ++++++++++++++ From cce0d0f4309f6a8aa81843b49145237ce0cea3d4 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 19 Feb 2019 16:42:04 +0100 Subject: [PATCH 13/25] Remove deprecated field --- docs/api/v3.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 9eb9446eadf..62358ab505d 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -132,7 +132,6 @@ Project details }, "default_version": "stable", "default_branch": "master", - "documentation_type": "sphinx_htmldir", "privacy_level": "public", "urls": { "documentation": "http://pip.pypa.io/en/stable/", From e2c9bf31d5157db785d103a5f4ee0ae57d655176 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 19 Feb 2019 20:56:06 +0100 Subject: [PATCH 14/25] Use "links" to make extra useful URLs available from objects --- docs/api/v3.rst | 121 +++++++++++++++++++++--------------------------- 1 file changed, 54 insertions(+), 67 deletions(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 62358ab505d..3ca88ac82e0 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -109,7 +109,6 @@ Project details **Example response**: - .. sourcecode:: js { @@ -133,6 +132,8 @@ Project details "default_version": "stable", "default_branch": "master", "privacy_level": "public", + "subproject_of": null, + "translation_of": null, "urls": { "documentation": "http://pip.pypa.io/en/stable/", "project": "https://pip.pypa.io/" @@ -145,23 +146,25 @@ Project details "setuptools", "virtualenv" ], - "users": [ - "/api/v3/users/dstufft/", - "/api/v3/users/pmoore/", - "/api/v3/users/xafer/", - "/api/v3/users/pradyunsg/" - ], - "versions": [ - "/api/v3/projects/pip/versions/stable/", - "/api/v3/projects/pip/versions/latest/", - "/api/v3/projects/pip/versions/19.0.2/" - ], - "subprojects": [ - "/api/v3/projects/pip-subproject/" - ], - "translations": [ - "/api/v3/projects/pip-es/" - ] + "users": { + "dstufft": {USER}, + "pmoore": {USER}, + "xafer": {USER}, + "pradyunsg": {USER} + }, + "active_versions": { + "stable: {VERSION}, + "latest: {VERSION}, + "19.0.2: {VERSION} + }, + "links": { + "self": "/api/v3/projects/pip/", + "users": "/api/v3/projects/pip/users/", + "versions": "/api/v3/projects/pip/versions/", + "builds": "/api/v3/projects/pip/builds/", + "subprojects": "/api/v3/projects/pip/subprojects/", + "translations": "/api/v3/projects/pip/translations/" + } } .. TODO: by default it should return *only active versions*, and @@ -260,9 +263,13 @@ Version detail "type": "tag", "last_build": {BUILD}, "downloads": { - "pdf": "//readthedocs.org/projects/pip/downloads/pdf/stable/", - "htmlzip": "//readthedocs.org/projects/pip/downloads/htmlzip/stable/", - "epub": "//readthedocs.org/projects/pip/downloads/epub/stable/" + "pdf": "https://readthedocs.org/projects/pip/downloads/pdf/stable/", + "htmlzip": "https://readthedocs.org/projects/pip/downloads/htmlzip/stable/", + "epub": "https://readthedocs.org/projects/pip/downloads/epub/stable/" + }, + "links": { + "self": "/api/v3/projects/pip/versions/stable/", + "builds": "/api/v3/projects/pip/versions/stable/builds/" } } @@ -328,15 +335,15 @@ For example, here is `Pip's build page`_. Build details +++++++++++++ -.. http:get:: /api/v3/builds/(int:build_id)/ +.. http:get:: /api/v3/projects/(str:project_slug)/builds/(int:build_id)/ - Retrieve details of a single build. + Retrieve details of a single build for a project. **Example request**: .. sourcecode:: bash - $ curl https://readthedocs.org/api/v3/builds/8592686/ + $ curl https://readthedocs.org/api/v3/projects/pip/builds/8592686/ **Example response**: @@ -358,10 +365,10 @@ Build details "commit": "6f808d743fd6f6907ad3e2e969c88a549e76db30", "builder": "build03", "cold_storage": false, - "commands": [ - "/api/v3/buildcommands/7281720376/", - "/api/v3/buildcommands/7281720377/", - ], + "links": { + "self": "/api/v3/projects/pip/builds/8592686/", + "commands": "/api/v3/projects/pip/builds/8592686/commands/" + } } @@ -401,15 +408,15 @@ Build details Builds listing ++++++++++++++ -.. http:get:: /api/v3/projects/(str:project_slug)/builds/(str:commit_hash)/ +.. http:get:: /api/v3/projects/(str:project_slug)/builds/ - Retrieve details for all the builds matching the commit hash on this project. + Retrieve list of all the builds on this project. **Example request**: .. sourcecode:: bash - $ curl https://readthedocs.org/api/v3/projects/pip/builds/24f652b/ + $ curl https://readthedocs.org/api/v3/projects/pip/builds/ **Example response**: @@ -417,34 +424,13 @@ Builds listing { "count": 15, - "next": "/api/v3/projects/pip/builds/24f652b/?limit=10&offset=10", + "next": "/api/v3/projects/pip/builds?limit=10&offset=10", "previous": null, "results": [BUILD] } - :reqheader Authorization: optional token to authenticate - - -.. http:get:: /api/v3/projects/(str:project_slug)/builds/running/ - - Retrieve details for all the builds that are currently building for this project. - - **Example request**: - - .. sourcecode:: bash - - $ curl https://readthedocs.org/api/v3/projects/pip/builds/running/ -. - **Example response**: - - .. sourcecode:: js - - { - "count": 15, - "next": "/api/v3/projects/pip/builds/running/?limit=10&offset=10", - "previous": null, - "results": [BUILD] - } + :query commit: commit hash to filter the builds returned by commit + :query running: whether or not to filter the builds returned by currently building :reqheader Authorization: optional token to authenticate @@ -479,7 +465,7 @@ Build triggering Build commands listing ++++++++++++++++++++++ -.. http:get:: /api/v3/builds/(int:build_id)/commands/ +.. http:get:: /api/v3/projects/(str:project_slug)/builds/(int:build_id)/commands/ Retrieve build command list of a single build. @@ -487,7 +473,7 @@ Build commands listing .. sourcecode:: bash - $ curl https://readthedocs.org/api/v3/builds/719263915/commands/ + $ curl https://readthedocs.org/api/v3/projects/pip/builds/719263915/commands/ . **Example response**: @@ -495,23 +481,18 @@ Build commands listing { "count": 15, - "next": "/api/v3/builds/719263915/commands/?limit=10&offset=10", + "next": "/api/v3/projects/pip/builds/719263915/commands/?limit=10&offset=10", "previous": null, "results": [BUILDCOMMAND] } - - :>json integer id: The ID of the build - :>json string date: The ISO-8601 datetime of the build. - :>json integer duration: The length of the build in seconds. - :reqheader Authorization: optional token to authenticate Build command details +++++++++++++++++++++ -.. http:get:: /api/v3/buildcommands/(int:buildcommand_id)/ +.. http:get:: /api/v3/projects/(str:project_slug)/builds/(int:build_id)/commands/(int:buildcommand_id) Retrieve build command detail. @@ -519,7 +500,7 @@ Build command details .. sourcecode:: bash - $ curl https://readthedocs.org/api/v3/buildcommands/9182639172/ + $ curl https://readthedocs.org/api/v3/projects/pip/builds/719263915/commands/9182639172/ . **Example response**: @@ -527,13 +508,19 @@ Build command details { "id": 9182639172, - "build": 719263915, + "build": {BUILD}, "created": "2018-06-19T15:15:59+00:00", "finished": "2018-06-19T15:16:58+00:00", "duration": 59, "command": "cat docs/config.py", "output": "...", - "exit_code": 0 + "exit_code": 0, + "links": { + "self": "/api/v3/projects/pip/builds/719263915/commands/9182639172/", + "build": "/api/v3/projects/pip/builds/719263915/", + "version": "/api/v3/projects/pip/versions/stable/", + "project": "/api/v3/projects/pip/" + } } :reqheader Authorization: optional token to authenticate From 400e837416b5922303385256c6da0f6c955e293d Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 19 Feb 2019 21:19:05 +0100 Subject: [PATCH 15/25] Make all JSON valid so they get colorized --- docs/api/v3.rst | 92 ++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 3ca88ac82e0..083a5c468af 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -62,19 +62,19 @@ Projects list **Example response**: - .. sourcecode:: js + .. sourcecode:: json { "count": 25, "next": "/api/v3/projects/limit=10&offset=10", "previous": null, - "results": [PROJECT] + "results": ["PROJECT"] } - :>json integer count: Total number of Projects. - :>json string next: URI for next set of Projects. - :>json string previous: URI for previous set of Projects. - :>json array results: Array of ``Project`` objects. + :>json integer count: Total number of projects. + :>json string next: URI for next set of projects. + :>json string previous: URI for previous set of projects. + :>json array results: Array of ``project`` objects. :query privacy_level: one of ``public``, ``private``, ``protected`` @@ -91,7 +91,7 @@ Projects list Considering that we are listing only projects associated with the authenticated user, we should not have performance problem with these filters - :reqheader Authorization: required token to authenticate + :reqheader Authorization: required token to authenticate. Project details @@ -109,7 +109,7 @@ Project details **Example response**: - .. sourcecode:: js + .. sourcecode:: json { "name": "Pip", @@ -124,7 +124,7 @@ Project details "programming_language": { "code": "py", "name": "Python" - } + }, "repository": { "url": "https://github.com/pypa/pip", "type": "git" @@ -137,8 +137,8 @@ Project details "urls": { "documentation": "http://pip.pypa.io/en/stable/", "project": "https://pip.pypa.io/" - } - "last_build": {BUILD}, + }, + "last_build": "{BUILD}", "tags": [ "disutils", "easy_install", @@ -147,15 +147,15 @@ Project details "virtualenv" ], "users": { - "dstufft": {USER}, - "pmoore": {USER}, - "xafer": {USER}, - "pradyunsg": {USER} + "dstufft": "{USER}", + "pmoore": "{USER}", + "xafer": "{USER}", + "pradyunsg": "{USER}" }, "active_versions": { - "stable: {VERSION}, - "latest: {VERSION}, - "19.0.2: {VERSION} + "stable": "{VERSION}", + "latest": "{VERSION}", + "19.0.2": "{VERSION}" }, "links": { "self": "/api/v3/projects/pip/", @@ -179,7 +179,7 @@ Project details .. TODO: complete the returned data docs once agreed on this. - :reqheader Authorization: optional token to authenticate + :reqheader Authorization: optional token to authenticate. :statuscode 200: Success :statuscode 404: There is no ``Project`` with this slug @@ -212,13 +212,13 @@ Versions listing **Example response**: - .. sourcecode:: js + .. sourcecode:: json { "count": 25, "next": "/api/v3/projects/pip/versions/?limit=10&offset=10", "previous": null, - "results": [VERSION] + "results": ["VERSION"] } :>json integer count: Total number of Projects. @@ -234,7 +234,7 @@ Versions listing :query active: one of ``true``, ``false`` :query built: one of ``true``, ``false`` - :reqheader Authorization: optional token to authenticate + :reqheader Authorization: optional token to authenticate. Version detail @@ -252,7 +252,7 @@ Version detail **Example response**: - .. sourcecode:: js + .. sourcecode:: json { "slug": "stable", @@ -261,7 +261,7 @@ Version detail "built": true, "active": true, "type": "tag", - "last_build": {BUILD}, + "last_build": "{BUILD}", "downloads": { "pdf": "https://readthedocs.org/projects/pip/downloads/pdf/stable/", "htmlzip": "https://readthedocs.org/projects/pip/downloads/htmlzip/stable/", @@ -282,7 +282,7 @@ Version detail :>json string last_build: Build object representing the last build of this version :>json array downloads: URLs to downloads of this version's documentation - :reqheader Authorization: optional token to authenticate + :reqheader Authorization: optional token to authenticate. :statuscode 200: Success :statuscode 404: There is no ``Version`` with this slug for this project @@ -297,7 +297,7 @@ Version edit **Example request**: - .. sourcecode:: js + .. sourcecode:: json { "active": true, @@ -310,9 +310,9 @@ Version edit **Example response**: - *See Version details* + `See Version details <#version-detail>`_ - :reqheader Authorization: required token to authenticate + :reqheader Authorization: required token to authenticate. :statuscode 204: Edited sucessfully :statuscode 400: Some field is invalid @@ -347,7 +347,7 @@ Build details **Example response**: - .. sourcecode:: js + .. sourcecode:: json { "id": 8592686, @@ -382,7 +382,7 @@ Build details :>json string builder: The hostname server that built the docs :>json string cold_storage: Whether the build was removed from database and stored externally - :reqheader Authorization: optional token to authenticate + :reqheader Authorization: optional token to authenticate. :statuscode 200: Success :statuscode 404: There is no ``Build`` with this ID @@ -400,9 +400,9 @@ Build details **Example response**: - *See Build details* + `See Build details <#build-details>`_ - :reqheader Authorization: optional token to authenticate + :reqheader Authorization: optional token to authenticate. Builds listing @@ -420,19 +420,19 @@ Builds listing **Example response**: - .. sourcecode:: js + .. sourcecode:: json { "count": 15, "next": "/api/v3/projects/pip/builds?limit=10&offset=10", "previous": null, - "results": [BUILD] + "results": ["BUILD"] } :query commit: commit hash to filter the builds returned by commit :query running: whether or not to filter the builds returned by currently building - :reqheader Authorization: optional token to authenticate + :reqheader Authorization: optional token to authenticate. Build triggering @@ -445,7 +445,7 @@ Build triggering **Example request**: - .. sourcecode:: js + .. sourcecode:: json { "version": "latest", @@ -453,9 +453,9 @@ Build triggering **Example response**: - *See Build details* + `See Build details <#build-details>`_ - :reqheader Authorization: required token to authenticate + :reqheader Authorization: required token to authenticate. :statuscode 201: Created sucessfully :statuscode 400: Some field is invalid @@ -474,19 +474,19 @@ Build commands listing .. sourcecode:: bash $ curl https://readthedocs.org/api/v3/projects/pip/builds/719263915/commands/ -. + **Example response**: - .. sourcecode:: js + .. sourcecode:: json { "count": 15, "next": "/api/v3/projects/pip/builds/719263915/commands/?limit=10&offset=10", "previous": null, - "results": [BUILDCOMMAND] + "results": ["BUILDCOMMAND"] } - :reqheader Authorization: optional token to authenticate + :reqheader Authorization: optional token to authenticate. Build command details @@ -501,14 +501,14 @@ Build command details .. sourcecode:: bash $ curl https://readthedocs.org/api/v3/projects/pip/builds/719263915/commands/9182639172/ -. + **Example response**: - .. sourcecode:: js + .. sourcecode:: json { "id": 9182639172, - "build": {BUILD}, + "build": "{BUILD}", "created": "2018-06-19T15:15:59+00:00", "finished": "2018-06-19T15:16:58+00:00", "duration": 59, @@ -523,4 +523,4 @@ Build command details } } - :reqheader Authorization: optional token to authenticate + :reqheader Authorization: optional token to authenticate. From 95f48f3c92c7a81f13b2aff9e3a57b1f93ed95ab Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 19 Feb 2019 21:42:24 +0100 Subject: [PATCH 16/25] Remove `last_build` from Project response --- docs/api/v3.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 083a5c468af..0569cfce223 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -138,7 +138,6 @@ Project details "documentation": "http://pip.pypa.io/en/stable/", "project": "https://pip.pypa.io/" }, - "last_build": "{BUILD}", "tags": [ "disutils", "easy_install", From aa095fe56aae7d1de16fad6a62b84316855471c5 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 19 Feb 2019 22:02:47 +0100 Subject: [PATCH 17/25] Use explicit roles names --- docs/api/v3.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 0569cfce223..520812a19f2 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -91,7 +91,7 @@ Projects list Considering that we are listing only projects associated with the authenticated user, we should not have performance problem with these filters - :reqheader Authorization: required token to authenticate. + :requestheader Authorization: required token to authenticate. Project details @@ -178,7 +178,7 @@ Project details .. TODO: complete the returned data docs once agreed on this. - :reqheader Authorization: optional token to authenticate. + :requestheader Authorization: optional token to authenticate. :statuscode 200: Success :statuscode 404: There is no ``Project`` with this slug @@ -233,7 +233,7 @@ Versions listing :query active: one of ``true``, ``false`` :query built: one of ``true``, ``false`` - :reqheader Authorization: optional token to authenticate. + :requestheader Authorization: optional token to authenticate. Version detail @@ -281,7 +281,7 @@ Version detail :>json string last_build: Build object representing the last build of this version :>json array downloads: URLs to downloads of this version's documentation - :reqheader Authorization: optional token to authenticate. + :requestheader Authorization: optional token to authenticate. :statuscode 200: Success :statuscode 404: There is no ``Version`` with this slug for this project @@ -311,7 +311,7 @@ Version edit `See Version details <#version-detail>`_ - :reqheader Authorization: required token to authenticate. + :requestheader Authorization: required token to authenticate. :statuscode 204: Edited sucessfully :statuscode 400: Some field is invalid @@ -381,7 +381,7 @@ Build details :>json string builder: The hostname server that built the docs :>json string cold_storage: Whether the build was removed from database and stored externally - :reqheader Authorization: optional token to authenticate. + :requestheader Authorization: optional token to authenticate. :statuscode 200: Success :statuscode 404: There is no ``Build`` with this ID @@ -401,7 +401,7 @@ Build details `See Build details <#build-details>`_ - :reqheader Authorization: optional token to authenticate. + :requestheader Authorization: optional token to authenticate. Builds listing @@ -431,7 +431,7 @@ Builds listing :query commit: commit hash to filter the builds returned by commit :query running: whether or not to filter the builds returned by currently building - :reqheader Authorization: optional token to authenticate. + :requestheader Authorization: optional token to authenticate. Build triggering @@ -454,7 +454,7 @@ Build triggering `See Build details <#build-details>`_ - :reqheader Authorization: required token to authenticate. + :requestheader Authorization: required token to authenticate. :statuscode 201: Created sucessfully :statuscode 400: Some field is invalid @@ -485,7 +485,7 @@ Build commands listing "results": ["BUILDCOMMAND"] } - :reqheader Authorization: optional token to authenticate. + :requestheader Authorization: optional token to authenticate. Build command details @@ -522,4 +522,4 @@ Build command details } } - :reqheader Authorization: optional token to authenticate. + :requestheader Authorization: optional token to authenticate. From f30d7197eebceec8a479f06dc4ac24433dad64dd Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 19 Feb 2019 22:17:32 +0100 Subject: [PATCH 18/25] Add CSRF abbr --- docs/api/v3.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 520812a19f2..35e9e723266 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -38,7 +38,8 @@ Session Session authentication is allowed on very specific endpoints, to allow hitting the API when reading documentation. -When a user is trying to authenticate via session, CSRF check is performed. +When a user is trying to authenticate via session, +:abbr:`CSRF (Cross-site request forgery)` check is performed. Resources From 4e7aa34facb8d75a1871869fb7fff88cf04964df Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 19 Feb 2019 22:17:45 +0100 Subject: [PATCH 19/25] Fix renamed document --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index faa26493db2..3e0bf6aa5ba 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -75,7 +75,7 @@ to help you create fantastic documentation for your project. webhooks badges - alternate_domains + custom_domains localization vcs subprojects From 208562c7699682ddd4fe14d1caf114a3e5081d64 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 19 Feb 2019 22:18:31 +0100 Subject: [PATCH 20/25] Link APIv3 --- docs/api/index.rst | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/api/index.rst b/docs/api/index.rst index 6e263bdefeb..66b8b884ac4 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -12,15 +12,10 @@ from Read the Docs. will be automatically redirected to HTTPS and non-GET/HEAD requests over insecure HTTP will fail. -.. tip:: - - It is a good idea to put your email address, application name, - or Read the Docs username into the user agent header of your requests. - That way the Read the Docs' team can contact you in the event of issues. - .. toctree:: :maxdepth: 3 + v3 v2 v1 From 0dff2d33f5991603c9ebe638c9a97d1401efac97 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 19 Feb 2019 23:13:44 +0100 Subject: [PATCH 21/25] Some fixes --- docs/api/v3.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 35e9e723266..3914d97007e 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -248,7 +248,7 @@ Version detail .. sourcecode:: bash - $ curl https://readthedocs.org/api/v3/projects/pip/versions/latest/ + $ curl https://readthedocs.org/api/v3/projects/pip/versions/stable/ **Example response**: @@ -273,6 +273,8 @@ Version detail } } + .. TODO: add a field showing what's the tag where ``stable`` points to + :>json string slug: The slug for this version :>json string verbose_name: The name of the version :>json string identifier: A version control identifier for this version (eg. the commit hash of the tag) @@ -371,6 +373,7 @@ Build details } } + .. TODO: maybe it's good to return the ``Config`` object used to run this build :>json integer id: The ID of the build :>json string date: The ISO-8601 datetime of the build. From b2e5ae5ad9a69d881b76a6c9dc2c852193f1a599 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 20 Feb 2019 12:26:26 +0100 Subject: [PATCH 22/25] More endpoints --- docs/api/v3.rst | 338 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 289 insertions(+), 49 deletions(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 3914d97007e..3638fb84f39 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -67,30 +67,21 @@ Projects list { "count": 25, - "next": "/api/v3/projects/limit=10&offset=10", + "next": "/api/v3/projects/?limit=10&offset=10", "previous": null, "results": ["PROJECT"] } - :>json integer count: Total number of projects. + :>json integer count: total number of projects. :>json string next: URI for next set of projects. :>json string previous: URI for previous set of projects. - :>json array results: Array of ``project`` objects. + :>json array results: array of ``project`` objects. - :query privacy_level: one of ``public``, ``private``, ``protected`` - - .. TODO: - - Add query string filters to narrow the query: - * privacy level - * language - * programming language - * repository url - * repository type - * all fields? - - Considering that we are listing only projects associated with the authenticated user, - we should not have performance problem with these filters + :query string privacy_level: one of ``public``, ``private``, ``protected``. + :query string language: language code as ``en``, ``es``, ``ru``, etc. + :query string programming_language: programming language code as ``py``, ``js``, etc. + :query string repository_url: URL of the repository. + :query string repository_type: one of ``git``, ``hg``, ``bzr``, ``svn``. :requestheader Authorization: required token to authenticate. @@ -113,6 +104,7 @@ Project details .. sourcecode:: json { + "id": 12345, "name": "Pip", "slug": "pip", "description": "Pip Installs Packages.", @@ -132,7 +124,10 @@ Project details }, "default_version": "stable", "default_branch": "master", - "privacy_level": "public", + "privacy_level": { + "code": "public", + "name": "Public", + }, "subproject_of": null, "translation_of": null, "urls": { @@ -146,12 +141,12 @@ Project details "setuptools", "virtualenv" ], - "users": { - "dstufft": "{USER}", - "pmoore": "{USER}", - "xafer": "{USER}", - "pradyunsg": "{USER}" - }, + "users": [ + "dstufft", + "pmoore", + "xafer", + "pradyunsg" + ], "active_versions": { "stable": "{VERSION}", "latest": "{VERSION}", @@ -167,18 +162,14 @@ Project details } } - .. TODO: by default it should return *only active versions*, and - having the possibility to return ``?only_active_versions=False`` or - something like that. Otherwise, including all the versions by - default will generate ton of data for some projects probably. - - :>json string name: The name of the project. :>json string slug: The project slug (used in the URL). :>json string description: An RST description of the project .. TODO: complete the returned data docs once agreed on this. + :query boolean inactive_versions: whether or not include inactive versions. + :requestheader Authorization: optional token to authenticate. :statuscode 200: Success @@ -229,10 +220,10 @@ Versions listing .. TODO: instead of an array, this could potentially be a dictionary with the slug as the key and a VERSION as value. - :query limit: limit number of object returned - :query offset: offset from the whole list returned - :query active: one of ``true``, ``false`` - :query built: one of ``true``, ``false`` + :query integer limit: limit number of object returned + :query integer offset: offset from the whole list returned + :query boolean active: whether return active versions only + :query boolean built: whether return only built version :requestheader Authorization: optional token to authenticate. @@ -240,7 +231,7 @@ Versions listing Version detail ++++++++++++++ -.. http:get:: /api/v3/projects/(string:project_slug)/version/(string:version_slug)/ +.. http:get:: /api/v3/projects/(string:project_slug)/versions/(string:version_slug)/ Retrieve details of a single version. @@ -255,11 +246,18 @@ Version detail .. sourcecode:: json { + "id": 71652437, "slug": "stable", "verbose_name": "stable", "identifier": "3a6b3995c141c0888af6591a59240ba5db7d9914", + "ref": "19.0.2", "built": true, "active": true, + "uploaded": true, + "privacy_level": { + "code": "public", + "name": "Public", + }, "type": "tag", "last_build": "{BUILD}", "downloads": { @@ -267,17 +265,22 @@ Version detail "htmlzip": "https://readthedocs.org/projects/pip/downloads/htmlzip/stable/", "epub": "https://readthedocs.org/projects/pip/downloads/epub/stable/" }, + "urls": { + "documentation": "https://pip.pypa.io/en/stable/", + "vcs": "https://github.com/pypa/pip/tree/19.0.2" + }, "links": { "self": "/api/v3/projects/pip/versions/stable/", - "builds": "/api/v3/projects/pip/versions/stable/builds/" + "builds": "/api/v3/projects/pip/versions/stable/builds/", + "project": "/api/v3/projects/pip/" } } - .. TODO: add a field showing what's the tag where ``stable`` points to - + :>json integer id: ID for this version on the database :>json string slug: The slug for this version :>json string verbose_name: The name of the version :>json string identifier: A version control identifier for this version (eg. the commit hash of the tag) + :>json string ref: tag or branch pointed by this version (available only when version is ``stable`` or ``latest``) :>json string built: Whether this version has been built :>json string active: Whether this version is active :>json string type: The type of this version (typically "tag" or "branch") @@ -303,11 +306,7 @@ Version edit { "active": true, - "privacy_level": "public", - "tags": [ - "python", - "packaging" - ] + "privacy_level": "public" } **Example response**: @@ -367,18 +366,54 @@ Build details "commit": "6f808d743fd6f6907ad3e2e969c88a549e76db30", "builder": "build03", "cold_storage": false, + "config": { + "version": "1", + "formats": [ + "htmlzip", + "epub", + "pdf" + ], + "python": { + "version": 3, + "install": [ + { + "requirements": ".../stable/tools/docs-requirements.txt" + } + ], + "use_system_site_packages": false + }, + "conda": null, + "build": { + "image": "readthedocs/build:latest" + }, + "doctype": "sphinx_htmldir", + "sphinx": { + "builder": "sphinx_htmldir", + "configuration": ".../stable/docs/html/conf.py", + "fail_on_warning": false + }, + "mkdocs": { + "configuration": null, + "fail_on_warning": false + }, + "submodules": { + "include": "all", + "exclude": [], + "recursive": true + } + }, "links": { "self": "/api/v3/projects/pip/builds/8592686/", + "project": "/api/v3/projects/pip/", + "version": "/api/v3/projects/pip/versions/latest/", "commands": "/api/v3/projects/pip/builds/8592686/commands/" } } - .. TODO: maybe it's good to return the ``Config`` object used to run this build - :>json integer id: The ID of the build :>json string date: The ISO-8601 datetime of the build. :>json integer duration: The length of the build in seconds. - :>json string state: The state of the build (one of "triggered", "building", "installing", "cloning", or "finished") + :>json string state: The state of the build (one of ``triggered``, ``building``, ``installing``, ``cloning``, or ``finished``) :>json boolean success: Whether the build was successful :>json string error: An error message if the build was unsuccessful :>json string commit: A version control identifier for this build (eg. the commit hash) @@ -432,8 +467,8 @@ Builds listing "results": ["BUILD"] } - :query commit: commit hash to filter the builds returned by commit - :query running: whether or not to filter the builds returned by currently building + :query string commit: commit hash to filter the builds returned by commit + :query boolean running: whether or not to filter the builds returned by currently building :requestheader Authorization: optional token to authenticate. @@ -465,6 +500,50 @@ Build triggering :statuscode 401: Not valid permissions +Build status +++++++++++++ + + +.. http:get:: /api/v3/projects/(str:project_slug)/builds/(int:build_id)/status/ + + Retrieve status details of a single build. + + **Example request**: + + .. sourcecode:: bash + + $ curl https://readthedocs.org/api/v3/projects/pip/builds/8592686/status/ + + **Example response**: + + .. sourcecode:: json + + { + "id": 8592686, + "version": "latest", + "project": "pip", + "created": "2018-06-19T15:15:59+00:00", + "finished": null, + "duration": null, + "state": { + "code": "triggered", + "name": "Triggered" + }, + "success": null, + "error": null, + "commit": "6f808d743fd6f6907ad3e2e969c88a549e76db30", + "builder": "build03", + "links": { + "self": "/api/v3/projects/pip/builds/8592686/", + "project": "/api/v3/projects/pip/", + "version": "/api/v3/projects/pip/versions/latest/", + "commands": "/api/v3/projects/pip/builds/8592686/commands/" + } + } + + :requestheader Authorization: optional token to authenticate. + + Build commands listing ++++++++++++++++++++++ @@ -511,7 +590,9 @@ Build command details { "id": 9182639172, - "build": "{BUILD}", + "build": 719263915, + "project": "pip", + "version": "stable", "created": "2018-06-19T15:15:59+00:00", "finished": "2018-06-19T15:16:58+00:00", "duration": 59, @@ -527,3 +608,162 @@ Build command details } :requestheader Authorization: optional token to authenticate. + + +Users +~~~~~ + +User detail ++++++++++++ + + +.. http:get:: /api/v3/users/(str:username) + + Retrieve details of a single user. + + **Example request**: + + .. sourcecode:: bash + + $ curl -H "Authorization: Token " https://readthedocs.org/api/v3/users/ + + **Example response**: + + .. sourcecode:: json + + { + "id": 25, + "username": "humitos", + "created": "2008-10-23T18:12:31+00:00", + "last_login": "2010-10-23T18:12:31+00:00", + "first_name": "Manuel", + "last_name": "Kaufmann", + "email": "humitos@readthedocs.org", + "links": { + "self": "/api/v3/users/humitos/", + "projects": "/api/v3/projects/?user=humitos" + } + } + + .. TODO: considering that ``/api/v3/projects/`` will return only + the projects for the authenticated user, the ``projects`` link + here won't work. + + On the other hand, ``/api/v3/projects/all/?user=humitos`` can't + be used because we will be mixing ``all`` as project slug with + our endpoint URL. + + :>json integer id: ID for the user on the database. + :>json string username: username for the user. + :>json string created: date and time when the user was created. + :>json string last_login: date and time for last time this user was logged in. + :>json string first_name: first name of the user. + :>json string last_name: last name of the user. + :>json string email: email of the user. + + :requestheader Authorization: required token to authenticate. + + +User listing +++++++++++++ + + +.. http:get:: /api/v3/projects/(str:project_slug)/users/ + + Retrieve list of users for a project. + + **Example request**: + + .. sourcecode:: bash + + $ curl -H "Authorization: Token " https://readthedocs.org/api/v3/projects/pip/users/ + + **Example response**: + + .. sourcecode:: json + + { + "count": 25, + "next": "/api/v3/projects/pip/users/limit=10&offset=10", + "previous": null, + "results": ["USER"] + } + + :>json integer count: total number of users. + :>json string next: URI for next set of users. + :>json string previous: URI for previous set of users. + :>json array results: array of ``user`` objects. + + :requestheader Authorization: optional token to authenticate. + + +Subprojects +~~~~~~~~~~~ + +Subprojects listing ++++++++++++++++++++ + + +.. http:get:: /api/v3/projects/(str:project_slug)/subprojects/ + + Retrieve a list of all sub-projects for a project. + + **Example request**: + + .. sourcecode:: bash + + $ curl -H "Authorization: Token " https://readthedocs.org/api/v3/projects/pip/subprojects/ + + **Example response**: + + .. sourcecode:: json + + { + "count": 25, + "next": "/api/v3/projects/pip/subprojects/?limit=10&offset=10", + "previous": null, + "results": ["PROJECT"] + } + + :>json integer count: total number of projects. + :>json string next: URI for next set of projects. + :>json string previous: URI for previous set of projects. + :>json array results: array of ``project`` objects. + + :requestheader Authorization: required token to authenticate. + + +Translations +~~~~~~~~~~~~ + +Translations listing +++++++++++++++++++++ + + +.. http:get:: /api/v3/projects/(str:project_slug)/translations/ + + Retrieve a list of all translations for a project. + + **Example request**: + + .. sourcecode:: bash + + $ curl -H "Authorization: Token " https://readthedocs.org/api/v3/projects/pip/translations/ + + **Example response**: + + .. sourcecode:: json + + { + "count": 25, + "next": "/api/v3/projects/pip/translations/?limit=10&offset=10", + "previous": null, + "results": ["PROJECT"] + } + + :>json integer count: total number of projects. + :>json string next: URI for next set of projects. + :>json string previous: URI for previous set of projects. + :>json array results: array of ``project`` objects. + + :requestheader Authorization: required token to authenticate. From 2adee183a6b5f05faf6d7ad482d8aed73a232919 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 20 Feb 2019 12:35:39 +0100 Subject: [PATCH 23/25] Use query attribute to (not)show the config object on build details --- docs/api/v3.rst | 48 +++--------------------------------------------- 1 file changed, 3 insertions(+), 45 deletions(-) diff --git a/docs/api/v3.rst b/docs/api/v3.rst index 3638fb84f39..6624f6791d1 100644 --- a/docs/api/v3.rst +++ b/docs/api/v3.rst @@ -344,7 +344,7 @@ Build details .. sourcecode:: bash - $ curl https://readthedocs.org/api/v3/projects/pip/builds/8592686/ + $ curl https://readthedocs.org/api/v3/projects/pip/builds/8592686/?include_config=true **Example response**: @@ -420,6 +420,8 @@ Build details :>json string builder: The hostname server that built the docs :>json string cold_storage: Whether the build was removed from database and stored externally + :query boolean include_config: whether or not include the configs used for this build. Default is ``false`` + :requestheader Authorization: optional token to authenticate. :statuscode 200: Success @@ -500,50 +502,6 @@ Build triggering :statuscode 401: Not valid permissions -Build status -++++++++++++ - - -.. http:get:: /api/v3/projects/(str:project_slug)/builds/(int:build_id)/status/ - - Retrieve status details of a single build. - - **Example request**: - - .. sourcecode:: bash - - $ curl https://readthedocs.org/api/v3/projects/pip/builds/8592686/status/ - - **Example response**: - - .. sourcecode:: json - - { - "id": 8592686, - "version": "latest", - "project": "pip", - "created": "2018-06-19T15:15:59+00:00", - "finished": null, - "duration": null, - "state": { - "code": "triggered", - "name": "Triggered" - }, - "success": null, - "error": null, - "commit": "6f808d743fd6f6907ad3e2e969c88a549e76db30", - "builder": "build03", - "links": { - "self": "/api/v3/projects/pip/builds/8592686/", - "project": "/api/v3/projects/pip/", - "version": "/api/v3/projects/pip/versions/latest/", - "commands": "/api/v3/projects/pip/builds/8592686/commands/" - } - } - - :requestheader Authorization: optional token to authenticate. - - Build commands listing ++++++++++++++++++++++ From 7146855e6d8d6f2974805506e70fc08fd3aa8601 Mon Sep 17 00:00:00 2001 From: Eric Holscher Date: Tue, 26 Feb 2019 13:55:53 -0300 Subject: [PATCH 24/25] Fix rstcheck --- docs/.rstcheck.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/.rstcheck.cfg b/docs/.rstcheck.cfg index fd9f1860335..4872be053df 100644 --- a/docs/.rstcheck.cfg +++ b/docs/.rstcheck.cfg @@ -1,4 +1,4 @@ [rstcheck] -ignore_directives=automodule,http:get,tabs,tab,prompt +ignore_directives=automodule,http:get,tabs,tab,prompt,http:patch,http:post ignore_roles=djangosetting,setting,featureflags,buildpyversions ignore_messages=(Duplicate implicit target name: ".*")|(Hyperlink target ".*" is not referenced) From c5a4cea25749b2990ba81fb15ac3a12eb05999b1 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 11 Mar 2019 15:34:16 +0100 Subject: [PATCH 25/25] Remove the user docs from the toctree --- docs/api/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/api/index.rst b/docs/api/index.rst index 66b8b884ac4..392b7b6357e 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -16,6 +16,5 @@ from Read the Docs. .. toctree:: :maxdepth: 3 - v3 v2 v1