Skip to content

Search: implement stable API #7255

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Aug 5, 2020
Merged
5 changes: 5 additions & 0 deletions docs/api/v3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1364,3 +1364,8 @@ Environment Variable delete
:requestheader Authorization: token to authenticate.

:statuscode 204: Environment variable deleted successfully

Additional APIs
---------------

- :ref:`Server side search API <server-side-search:api>`.
120 changes: 120 additions & 0 deletions docs/server-side-search.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,123 @@ and then click on :guilabel:`Search Analytics`.
Search analytics demo

.. _Elasticsearch: https://www.elastic.co/products/elasticsearch

API
---

Search is exposed through our API that's proxied from the domain where your docs are being served.
This is ``https://docs.readthedocs.io/_/api/v2/search`` for the ``docs`` project, for example.

.. warning::

This API isn't stable yet, some small things may change in the future.
Comment on lines +74 to +76
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm leaving this warning since the response will change when we start returning relative paths

Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we should do the relative path work in another PR after merging this one, before shipping it? Seems nice to get it all done together if possible.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, I can start working in another PR


.. http:get:: /_/api/v2/search/

Return a list of search results for a project,
including results from its :doc:`/subprojects`.
Results are divided into sections with highlights of the matching term.

.. Request

:query q: Search query
:query project: Project slug
:query version: Version slug

.. Response

:>json string type: The type of the result, currently page is the only type.
:>json string project: The project slug
:>json string version: The version slug
:>json string title: The title of the page
:>json string link: An absolute URL to the resulting page
:>json object highlights: An object containing a list of substrings with matching terms.
Note that the text is HTML escaped with the matching terms inside a <span> tag.
:>json object blocks:

A list of block objects containing search results from the page.
Currently, there are two types of blocks:

- section: A page section with a linkable anchor (``id`` attribute).
- domain: A Sphinx :doc:`domain <sphinx:usage/restructuredtext/domains>`
with a linkable anchor (``id`` attribute).


**Example request**:

.. tabs::

.. code-tab:: bash

$ curl "https://docs.readthedocs.io/_/api/v2/search/?project=docs&version=latest&q=server%20side%20search"

.. code-tab:: python

import requests
URL = 'https://docs.readthedocs.io/_/api/v2/search/'
params = {
'q': 'server side search',
'project': 'docs',
'version': 'latest',
}
response = requests.get(URL, params=params)
print(response.json())

**Example response**:

.. sourcecode:: json

{
"count": 41,
"next": "https://docs.readthedocs.io/api/v2/search/?page=2&project=read-the-docs&q=server+side+search&version=latest",
"previous": null,
"results": [
{
"type": "page",
"project": "docs",
"version": "latest",
"title": "Server Side Search",
"link": "https://docs.readthedocs.io/en/latest/server-side-search.html",
"highlights": {
"title": [
"<span>Server</span> <span>Side</span> <span>Search</span>"
]
},
"blocks": [
{
"type": "section",
"id": "server-side-search",
"title": "Server Side Search",
"content": "Read the Docs provides full-text search across all of the pages of all projects, this is powered by Elasticsearch.",
"highlights": {
"title": [
"<span>Server</span> <span>Side</span> <span>Search</span>"
],
"content": [
"You can <span>search</span> all projects at https:&#x2F;&#x2F;readthedocs.org&#x2F;<span>search</span>&#x2F"
]
}
},
{
"type": "domain",
"role": "http:get",
"name": "/_/api/v2/search/",
"id": "get--_-api-v2-search-",
"content": "Retrieve search results for docs",
"highlights": {
"name": [""],
"content": ["Retrieve <span>search</span> results for docs"]
}
}
]
},
]
}

Authentication and authorization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you are using :ref:`private versions <versions:privacy levels>`,
users will only be allowed to search projects they have permissions over.
Authentication and authorization is done using the current session,
or any of the valid :doc:`sharing methods </commercial/sharing>`.
1 change: 1 addition & 0 deletions readthedocs/api/v2/proxied_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
api_footer_urls = [
url(r'footer_html/', ProxiedFooterHTML.as_view(), name='footer_html'),
url(r'docsearch/$', ProxiedPageSearchAPIView.as_view(), name='doc_search'),
url(r'search/$', ProxiedPageSearchAPIView.as_view(new_api=True), name='search_api'),
]

urlpatterns = api_footer_urls
Expand Down
Loading