From 36b98a936b041b21fa2b18ca8d1e7a23353dcf79 Mon Sep 17 00:00:00 2001 From: Leonardo Rossi Date: Tue, 19 Jul 2016 15:59:49 +0200 Subject: [PATCH] docs: improve documentation * Improves documentation. (addresses #99) Signed-off-by: Leonardo Rossi --- invenio_records_rest/config.py | 185 +++++++++++++++++++++++++++++++-- invenio_records_rest/errors.py | 2 +- invenio_records_rest/facets.py | 23 +++- invenio_records_rest/sorter.py | 6 +- invenio_records_rest/views.py | 31 ++++-- 5 files changed, 222 insertions(+), 25 deletions(-) diff --git a/invenio_records_rest/config.py b/invenio_records_rest/config.py index e5dd41ff..d24d7295 100644 --- a/invenio_records_rest/config.py +++ b/invenio_records_rest/config.py @@ -58,6 +58,144 @@ def _(x): max_result_window=10000, ), ) +"""Default REST endpoints loaded. + +This option can be overwritten to describe the endpoints of the different +record types. Each endpoint is in charge of managing all its CRUD operations +(GET, POST, PUT, DELETE, ...). + +The structure of the dictionary is as follows: + +.. code-block:: python + + from invenio_records_rest.query import es_search_factory + + + def search_factory(*args, **kwargs): + if not current_user.is_authenticated: + abort(401) + return es_search_factory(*args, **kwargs) + + + def permission_check_factory(): + def check_title(record, *args, **kwargs): + def can(self): + if record['title'] == 'Hello World': + return True + return type('Check', (), {'can': can})() + + + RECORDS_REST_ENDPOINTS = { + "record-pid-type": { + "create_permission_factory_imp": permission_check_factory(), + "default_media_type": "application/json", + "delete_permission_factory_imp": permission_check_factory(), + "item_route": ""/recods/"", + "links_factory_imp": ("invenio_records_rest.links:" + "default_links_factory"), + "list_route": "/records/", + "max_result_window": 10000, + "pid_fetcher": "", + "pid_minter": "", + "pid_type": "", + "read_permission_factory_imp": permission_check_factory(), + "record_class": "mypackage.api:MyRecord", + "record_loaders": { + "application/json": "mypackage.loaders:json_loader" + }, + "record_serializers": { + "application/json": "mypackage.utils:my_json_serializer" + }, + "search_class": "mypackage.utils:mysearchclass", + "search_factory_imp": search_factory(), + "search_index": "elasticsearch-index-name", + "search_serializers": { + "application/json": "mypackage.utils:my_json_search_serializer" + }, + "search_type": "elasticsearch-doc-type", + "suggesters": { + "my_url_param_to_complete": { + "completion": { + "field": "suggest_byyear_elasticsearch_field", + "size": 10, + "context": "year" + } + }, + }, + "update_permission_factory_imp": permission_check_factory(), + "use_options_view": True, + }, + } + +:param create_permission_factory_imp: Import path to factory that crcreate + permission object for a given record. + +:param default_media_type: Default media type for both records and search. + +:param delete_permission_factory_imp: Import path to factory that creates a + delete permission object for a given record. + +:param item_route: URL template for a single record. + +:param links_factory_imp: Factory for record links generation. + +:param list_route: Base URL for the records endpoint. + +:param max_result_window: Maximum total number of records retrieved from a + query. + +:param pid_type: It specifies the record pid type. It's used also to build the + endpoint name. Required. + E.g. ``url_for('record-pid-type_list')`` to point to the records list. + +:param pid_fetcher: It identifies the registered fetcher name + (see class:`invenio_pidstore:_PIDStoreState`). Required. + +:param pid_minter: It identifies the registered minter name + (see class:`invenio_pidstore:_PIDStoreState`). Required. + +:param read_permission_factory_imp: Import path to factory that creates a + read permission object for a given record. + +:param record_class: Name of the record API class. + +:param record_loaders: It contains the list of record deserializers for + supperted formats. + +:param record_serializers: It contains the list of record serializers for + supported formats. + +:param search_class: Import path or class object for the object in charge of + execute the search queries. The default search class is + class:`invenio_search.api.RecordsSearch`. + For more information about resource loading, see + class:`elasticsearch_dsl.Search`. + +:param search_factory_imp: Factory that parse query that returns a tuple with + search instance and URL arguments. + +:param search_index: Name of the search index used when searching records. + +:param search_serializers: It contains the list of records serializers for all + supported format. This configuration differ from the previous because in + this case it handle a list of records resulted by a search query instead of + a single record. + +:param search_type: Name of the search type used when searching records. + +:param suggesters: Suggester fields configuration. Any element of the + dictionary represents a suggestion field. The key is used as url query + parameter. + To have more information about suggestion configuration, you can read + suggesters section on ElasticSearch documentation. + Note: only completion suggessters are supported. + +:param update_permission_factory_imp: Import path to factory that creates a + update permission object for a given record. + +:param use_options_view: Determines if a special option view should be + installed. +""" RECORDS_REST_DEFAULT_LOADERS = { 'application/json': lambda: request.get_json(), @@ -65,9 +203,11 @@ def _(x): } """Default data loaders per request mime type. -This option can be overritten in each REST endpoint as follows:: +This option can be overritten in each REST endpoint as follows: + +.. code-block:: python - { + RECORDS_REST_ENDPOINTS = { "recid": { ... "record_loaders": { @@ -97,13 +237,17 @@ def _(x): ) """Sort options for default sorter factory. -The structure of the dictionary is as follows:: +The structure of the dictionary is as follows: - { +.. code-block:: python + + RECORDS_REST_SORT_OPTIONS = { "": { - "fields": ["", "", ...], - "title": "", - "default_order": "<default sort order in search-ui>", + "<sort-field-name>": { + "fields": ["<search_field>", "<search_field>", ...], + "title": "<title displayed to end user in search-ui>", + "default_order": "<default sort order in search-ui>", + } } } @@ -124,7 +268,19 @@ def _(x): noquery='mostrecent', ) ) -"""Default sort option per index with/without query string.""" +"""Default sort option per index with/without query string. + +The structure of the dictionary is as follows: + +.. code-block:: python + + RECORDS_REST_DEFAULT_SORT = { + "<index or index alias>": { + "query": "<default-sort-if-a-query-is-passed-from-url>", + "noquery": "<default-sort-if-no-query-in-passed-from-url>" + } + } +""" RECORDS_REST_FACETS = dict( records=dict( @@ -138,9 +294,11 @@ def _(x): ) """Facets per index for the default facets factory. -The structure of the dictionary is as follows:: +The structure of the dictionary is as follows: + +.. code-block:: python - { + RECORDS_REST_FACETS = { "<index or index alias>": { "aggs": { "<key>": <aggregation definition>, @@ -159,6 +317,13 @@ def _(x): """ RECORDS_REST_DEFAULT_CREATE_PERMISSION_FACTORY = deny_all +"""Default crete permission factory: reject any request.""" + RECORDS_REST_DEFAULT_READ_PERMISSION_FACTORY = check_elasticsearch +"""Default read permission factory: check if the record exists.""" + RECORDS_REST_DEFAULT_UPDATE_PERMISSION_FACTORY = deny_all +"""Default update permission factory: reject any request.""" + RECORDS_REST_DEFAULT_DELETE_PERMISSION_FACTORY = deny_all +"""Default delete permission factory: reject any request.""" diff --git a/invenio_records_rest/errors.py b/invenio_records_rest/errors.py index 765a2283..b1db53b1 100644 --- a/invenio_records_rest/errors.py +++ b/invenio_records_rest/errors.py @@ -34,7 +34,7 @@ # Search # class MaxResultWindowRESTError(RESTException): - """Maximum number of results passed.""" + """Maximum number of passed results have been reached.""" code = 400 description = 'Maximum number of results have been reached.' diff --git a/invenio_records_rest/facets.py b/invenio_records_rest/facets.py index f2c1433c..4a785e13 100644 --- a/invenio_records_rest/facets.py +++ b/invenio_records_rest/facets.py @@ -34,14 +34,25 @@ def terms_filter(field): - """Create a term filter.""" + """Create a term filter. + + :param field: field name. + :returns: function that returns the Terms query. + """ def inner(values): return Q('terms', **{field: values}) return inner def range_filter(field, start_date_math=None, end_date_math=None, **kwargs): - """Create a range filter.""" + """Create a range filter. + + :param field: field name + :param start_date_math: starting date + :param end_date_math: ending date + :param kwargs: addition arguments passed to the Range query. + :returns: function that returns the Range query. + """ def inner(values): if len(values) != 1 or values[0].count('--') != 1 or values[0] == '--': raise RESTValidationError( @@ -121,7 +132,13 @@ def _aggregations(search, definitions): def default_facets_factory(search, index): - """Add facets to query.""" + """Add a default facets to query. + + :param search: basic search object + :param index: index name + :returns: a tuple containing the new search object and a dictionary with + all fields and values used. + """ urlkwargs = MultiDict() facets = current_app.config['RECORDS_REST_FACETS'].get(index) diff --git a/invenio_records_rest/sorter.py b/invenio_records_rest/sorter.py index 4de84c0b..3d0e14b9 100644 --- a/invenio_records_rest/sorter.py +++ b/invenio_records_rest/sorter.py @@ -51,6 +51,7 @@ def geolocation_sort(field_name, argument, unit, mode=None, :param unit: Distance unit (e.g. km). :param mode: Sort mode (avg, min, max). :param distance_type: Distance calculation mode. + :returns: Function that returns geolocation sort field. """ def inner(asc): locations = request.values.getlist(argument, type=str) @@ -73,7 +74,7 @@ def parse_sort_field(field_value): """Parse a URL field. :param field_value: Field value (e.g. 'key' or '-key'). - :returns: Tuple of (field, ascending). + :returns: Tuple of (field, ascending) as string and boolean. """ if field_value.startswith("-"): return (field_value[1:], False) @@ -98,6 +99,7 @@ def eval_field(field, asc): :param field: Field definition (string, dict or callable). :param asc: ``True`` if order is ascending, ``False`` if descending. + :returns: Dictionary with the sort field query. """ if isinstance(field, dict): if asc: @@ -118,7 +120,7 @@ def eval_field(field, asc): def default_sorter_factory(search, index): - """Sort a query. + """Default sort query factory. :param query: Search query. :param index: Index to search in. diff --git a/invenio_records_rest/views.py b/invenio_records_rest/views.py index 39993c49..6df55c79 100644 --- a/invenio_records_rest/views.py +++ b/invenio_records_rest/views.py @@ -128,12 +128,14 @@ def create_url_rules(endpoint, list_route=None, item_route=None, """Create Werkzeug URL rules. :param endpoint: Name of endpoint. - :param list_route: record listing URL route . Required. - :param item_route: record URL route (must include ``<pid_value>`` pattern). + :param list_route: Record listing URL route. Required. + :param item_route: Record URL route (must include ``<pid_value>`` pattern). Required. :param pid_type: Persistent identifier type for endpoint. Required. - :param template: Template to render. Defaults to - ``invenio_records_ui/detail.html``. + :param pid_minter: It identifies the registered minter name. + (see class:`invenio_pidstore:_PIDStoreState`). Required. + :param pid_fetcher: It identifies the registered fetcher name + (see class:`invenio_pidstore:_PIDStoreState`). Required. :param read_permission_factory_imp: Import path to factory that creates a read permission object for a given record. :param create_permission_factory_imp: Import path to factory that creates a @@ -142,18 +144,29 @@ def create_url_rules(endpoint, list_route=None, item_route=None, update permission object for a given record. :param delete_permission_factory_imp: Import path to factory that creates a delete permission object for a given record. + :param record_class: Name of the record API class. + :param record_serializers: Serializers used for records. + :param record_loaders: It contains the list of record deserializers for + supperted formats. + :param search_class: Import path or class object for the object in charge + of execute the search queries. The default search class is + class:`invenio_search.api.RecordsSearch`. + For more information about resource loading, see + class:`elasticsearch_dsl.Search`. + :param search_serializers: Serializers used for search results. :param search_index: Name of the search index used when searching records. :param search_type: Name of the search type used when searching records. - :param record_class: Name of the record API class. - :param record_serializers: serializers used for records. - :param search_serializers: serializers used for search results. - :param default_media_type: default media type for both records and search. - :param max_result_window: maximum number of results that Elasticsearch can + :param default_media_type: Default media type for both records and search. + :param max_result_window: Maximum number of results that Elasticsearch can provide for the given search index without use of scroll. This value should correspond to Elasticsearch ``index.max_result_window`` value for the index. :param use_options_view: Determines if a special option view should be installed. + :param search_factory_imp: Factory that parse query that returns a tuple + with search instance and URL arguments. + :param links_factory_imp: Factory for record links generation. + :param suggesters: Suggester fields configuration. :returns: a list of dictionaries with can each be passed as keywords arguments to ``Blueprint.add_url_rule``.