From d0100f506268892af60f706275cb2c9a56fedef8 Mon Sep 17 00:00:00 2001 From: kuzzle Date: Mon, 29 Apr 2019 18:28:56 +0200 Subject: [PATCH] Release 2.1.1 (#289) * Add documentation page about mappings (#271) Adds a documentation essentials page about mappings: dynamic mapping policy collection metadata properties types definitions Also update SDKs See kuzzleio/kuzzle#1257 * Embedded protocols (#286) Documentation for embedded protocols, notably for MQTT. * Extending the JS SDK with controllers (#284) Add a page about how to extend the JS SDK with custom controllers. https://deploy-preview-284--kuzzle-doc-v2.netlify.com/sdk-reference/js/6/extend-sdk/ Also document: - BaseController class - Kuzzle.useController method See https://github.com/kuzzleio/sdk-javascript/pull/388 * [KZL-907] Getting started dev plugin (#276) ## What does this PR do? This PR responds to this [ticket](https://jira.kaliop.net/browse/KZL-907). Also, it increases the readability of documentation's plugin part. ### How should this be manually tested? [Netify](https://deploy-preview-276--kuzzle-doc-v2.netlify.com/plugins/1/essentials/introduction/) ### Other changes - Re-arrange plugin documentation path - Update dead link in boilerplate repository ### Boyscout Prettier * Release 2.1.1 --- helpers/handlebars.js | 5 +- package-lock.json | 2 +- package.json | 2 +- .../1/controller-collection/create/index.md | 34 +- .../get-mapping/index.md | 40 +- .../update-mapping/index.md | 33 +- .../1/essentials/database-mappings/index.md | 175 +++++++ src/guide/1/essentials/persisted/index.md | 52 +- src/guide/1/essentials/plugins/index.md | 38 +- src/plugins/1/accessors/trigger/index.md | 19 +- .../Documentation}/index.md | 56 ++- src/plugins/1/controllers/index.md | 5 + .../1/essentials/getting-started/index.md | 116 +---- src/plugins/1/essentials/index.md | 4 +- .../1/essentials/introduction/index.md | 19 + src/plugins/1/essentials/strategies/index.md | 443 ------------------ src/plugins/1/events/index.md | 2 +- src/plugins/1/events/intro/index.md | 4 +- .../hooks => hooks/Documentation}/index.md | 24 +- src/plugins/1/hooks/index.md | 5 + src/plugins/1/index.md | 3 - src/plugins/1/manual-setup/config/index.md | 25 + src/plugins/1/manual-setup/index.md | 6 + .../1/manual-setup/init-function/index.md | 33 ++ .../1/manual-setup/prerequisites/index.md | 37 ++ .../pipes => pipes/Documentation}/index.md | 37 +- src/plugins/1/pipes/index.md | 5 + .../1/strategies/auth-functions/index.md | 383 +++++++++++++++ src/plugins/1/strategies/index.md | 5 + src/plugins/1/strategies/overview/index.md | 68 +++ .../1/essentials/getting-started/index.md | 4 +- .../broadcast/index.md | 0 .../disconnect/index.md | 0 src/protocols/1/methods/index.md | 6 + .../1/{essentials => methods}/init/index.md | 0 .../joinchannel/index.md | 0 .../leavechannel/index.md | 0 .../1/{essentials => methods}/notify/index.md | 0 .../1/native-protocols/http/index.md | 32 ++ src/protocols/1/native-protocols/index.md | 6 + .../1/native-protocols/mqtt/index.md | 185 ++++++++ .../1/native-protocols/socketio/index.md | 25 + .../1/native-protocols/websocket/index.md | 25 + .../cpp/1/collection/create/index.md | 27 +- .../1/collection/create/snippets/create.cpp | 4 + .../cpp/1/collection/get-mapping/index.md | 2 +- .../get-mapping/snippets/get-mapping.cpp | 2 +- .../cpp/1/collection/update-mapping/index.md | 22 +- .../snippets/update-mapping.cpp | 4 + .../go/1/collection/create/index.md | 31 +- .../go/1/collection/create/snippets/create.go | 2 +- .../go/1/collection/update-mapping/index.md | 25 +- .../update-mapping/snippets/update-mapping.go | 2 +- .../js/6/base-controller/index.md | 7 + .../6/base-controller/introduction/index.md | 12 + .../js/6/base-controller/properties/index.md | 15 + .../js/6/base-controller/query/index.md | 54 +++ .../js/6/collection/create/index.md | 22 +- .../js/6/collection/create/snippets/create.js | 4 + .../js/6/collection/get-mapping/index.md | 2 +- .../get-mapping/snippets/get-mapping.js | 2 +- .../js/6/collection/update-mapping/index.md | 21 +- .../update-mapping/snippets/update-mapping.js | 4 + src/sdk-reference/js/6/extend-sdk/index.md | 99 ++++ src/sdk-reference/js/6/kuzzle/index.md | 3 +- src/sdk-reference/js/6/kuzzle/query/index.md | 2 +- .../js/6/kuzzle/use-controller/index.md | 33 ++ .../use-controller/snippets/use-controller.js | 35 ++ .../snippets/use-controller.test.yml | 10 + test/lib/helpers/logger.js | 2 +- test/templates/controller.tpl.js | 11 + 71 files changed, 1647 insertions(+), 775 deletions(-) create mode 100644 src/guide/1/essentials/database-mappings/index.md rename src/plugins/1/{essentials/controllers => controllers/Documentation}/index.md (82%) create mode 100644 src/plugins/1/controllers/index.md create mode 100644 src/plugins/1/essentials/introduction/index.md delete mode 100644 src/plugins/1/essentials/strategies/index.md rename src/plugins/1/{essentials/hooks => hooks/Documentation}/index.md (73%) create mode 100644 src/plugins/1/hooks/index.md create mode 100644 src/plugins/1/manual-setup/config/index.md create mode 100644 src/plugins/1/manual-setup/index.md create mode 100644 src/plugins/1/manual-setup/init-function/index.md create mode 100644 src/plugins/1/manual-setup/prerequisites/index.md rename src/plugins/1/{essentials/pipes => pipes/Documentation}/index.md (79%) create mode 100644 src/plugins/1/pipes/index.md create mode 100644 src/plugins/1/strategies/auth-functions/index.md create mode 100644 src/plugins/1/strategies/index.md create mode 100644 src/plugins/1/strategies/overview/index.md rename src/protocols/1/{essentials => methods}/broadcast/index.md (100%) rename src/protocols/1/{essentials => methods}/disconnect/index.md (100%) create mode 100644 src/protocols/1/methods/index.md rename src/protocols/1/{essentials => methods}/init/index.md (100%) rename src/protocols/1/{essentials => methods}/joinchannel/index.md (100%) rename src/protocols/1/{essentials => methods}/leavechannel/index.md (100%) rename src/protocols/1/{essentials => methods}/notify/index.md (100%) create mode 100644 src/protocols/1/native-protocols/http/index.md create mode 100644 src/protocols/1/native-protocols/index.md create mode 100644 src/protocols/1/native-protocols/mqtt/index.md create mode 100644 src/protocols/1/native-protocols/socketio/index.md create mode 100644 src/protocols/1/native-protocols/websocket/index.md create mode 100644 src/sdk-reference/js/6/base-controller/index.md create mode 100644 src/sdk-reference/js/6/base-controller/introduction/index.md create mode 100644 src/sdk-reference/js/6/base-controller/properties/index.md create mode 100644 src/sdk-reference/js/6/base-controller/query/index.md create mode 100644 src/sdk-reference/js/6/extend-sdk/index.md create mode 100644 src/sdk-reference/js/6/kuzzle/use-controller/index.md create mode 100644 src/sdk-reference/js/6/kuzzle/use-controller/snippets/use-controller.js create mode 100644 src/sdk-reference/js/6/kuzzle/use-controller/snippets/use-controller.test.yml create mode 100644 test/templates/controller.tpl.js diff --git a/helpers/handlebars.js b/helpers/handlebars.js index 659eeb2e7..8d999067c 100644 --- a/helpers/handlebars.js +++ b/helpers/handlebars.js @@ -66,8 +66,7 @@ module.exports = { return new SafeString(title); }, - since: version => `

Added in v${version}

`, + since: version => `

Added in ${version}

`, - deprecated: version => `

Deprecated since v${version}

` + deprecated: version => `

Deprecated since ${version}

` }; - diff --git a/package-lock.json b/package-lock.json index 78d77f194..247073032 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "kuzzleio-documentation", - "version": "2.1.0", + "version": "2.1.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8fbee4784..613422170 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kuzzleio-documentation", - "version": "2.1.0", + "version": "2.1.1", "description": "Kuzzle Documentation", "main": "index.js", "scripts": { diff --git a/src/api/1/controller-collection/create/index.md b/src/api/1/controller-collection/create/index.md index 173f82eb6..86cfb6ac3 100644 --- a/src/api/1/controller-collection/create/index.md +++ b/src/api/1/controller-collection/create/index.md @@ -11,9 +11,15 @@ Creates a new [collection]({{ site_base_path }}guide/1/essentials/persisted), in {{{since "1.3.0"}}} -You can also provide an optional body with a data mapping that allow you to exploit the full capabilities of our persistent data storage layer. +You can also provide an optional body with a [collection mapping]({{ site_base_path }}guide/1/essentials/database-mappings) allowing you to exploit the full capabilities of our persistent data storage layer. -This method will only update the mapping if the collection already exists. +This method will only update the mapping when the collection already exists. + +{{{since "1.7.1"}}} + +You can define the collection [dynamic mapping policy]({{ site_base_path}}guide/1/essentials/database-mappings/#dynamic-mapping-policy) by setting the `dynamic` field to the desired value. + +You can define [collection additional metadata]({{ site_base_path}}guide/1/essentials/database-mappings/#collection-metadata) within the `_meta` root field. --- @@ -29,6 +35,10 @@ Body: ```js { + "dynamic": "[false|true|strict]", + "_meta": { + "field": "value" + }, "properties": { "field1": { "type": "integer" @@ -37,8 +47,8 @@ Body: "type": "keyword" }, "field3": { - "type": "date", - "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" } } } @@ -54,6 +64,10 @@ Body: "controller": "collection", "action": "create", "body": { + "dynamic": "[false|true|strict]", + "_meta": { + "field": "value" + }, "properties": { "field1": { "type": "integer" @@ -62,8 +76,8 @@ Body: "type": "keyword" }, "field3": { - "type": "date", - "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" } } } @@ -74,8 +88,8 @@ Body: ## Arguments -* `collection`: collection name to create -* `index`: index name that will host the new collection +* `collection`: name of the collection to create +* `index`: index that will host the new collection --- @@ -83,7 +97,9 @@ Body: ### Optional: -* `properties`: object describing the data mapping to associate to the new collection, using [Elasticsearch mapping format](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping.html). +* `dynamic`: [dynamic mapping policy]({{ site_base_path}}guide/1/essentials/database-mappings/#dynamic-mapping-policy) for new fields. Allowed values: `true` (default), `false`, `strict` +* `_meta`: [collection additional metadata]({{ site_base_path}}guide/1/essentials/database-mappings/#collection-metadata) stored next to the collection +* `properties`: object describing the data mapping to associate to the new collection, using [Elasticsearch types definitions format]({{ site_base_path}}guide/1/essentials/database-mappings/#properties-types-definition) --- diff --git a/src/api/1/controller-collection/get-mapping/index.md b/src/api/1/controller-collection/get-mapping/index.md index e77eed821..3c43842ba 100644 --- a/src/api/1/controller-collection/get-mapping/index.md +++ b/src/api/1/controller-collection/get-mapping/index.md @@ -7,7 +7,11 @@ title: getMapping {{{since "1.0.0"}}} -Returns a collection mapping. +Returns the collection mapping. + +{{{since "1.7.1"}}} + +Also returns the collection [dynamic mapping policy]({{ site_base_path}}guide/1/essentials/database-mappings/#dynamic-mapping-policy) and [collection additional metadata]({{ site_base_path}}guide/1/essentials/database-mappings/#collection-metadata). --- @@ -47,13 +51,17 @@ Returns a mapping object with the following structure: ``` - |- mappings - |- - |- properties - |- mapping for field 1 - |- mapping for field 2 - |- ... - |- mapping for field n + |- mappings + |- + |- dynamic + |- _meta + |- metadata 1 + |- metadata 1 + |- properties + |- mapping for field 1 + |- mapping for field 2 + |- ... + |- mapping for field n ``` ### Example: @@ -71,16 +79,16 @@ Returns a mapping object with the following structure: "": { "mappings": { "": { + "dynamic": "true", + "_meta": { + "metadata1": "value1" + }, "properties": { - "field1": { - "type": "integer" - }, - "field2": { - "type": "keyword" - }, + "field1": { "type": "integer" }, + "field2": { "type": "keyword" }, "field3": { - "type": "date", - "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" } } } diff --git a/src/api/1/controller-collection/update-mapping/index.md b/src/api/1/controller-collection/update-mapping/index.md index 333f62d04..8b7ac9442 100644 --- a/src/api/1/controller-collection/update-mapping/index.md +++ b/src/api/1/controller-collection/update-mapping/index.md @@ -9,6 +9,12 @@ title: updateMapping Updates a collection mapping. +{{{since "1.7.1"}}} + +You can define the collection [dynamic mapping policy]({{ site_base_path}}guide/1/essentials/database-mappings/#dynamic-mapping-policy) by setting the `dynamic` field to the desired value. + +You can define [collection additional metadata]({{ site_base_path}}guide/1/essentials/database-mappings/#collection-metadata) within the `_meta` root field. + --- ## Query Syntax @@ -23,6 +29,10 @@ Body: ```js { + "dynamic": "[true|false|strict]", + "_meta": { + "field": "value" + }, "properties": { "field1": { "type": "integer" @@ -31,8 +41,8 @@ Body: "type": "keyword" }, "field3": { - "type": "date", - "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" } } } @@ -46,8 +56,11 @@ Body: "collection": "", "controller": "collection", "action": "updateMapping", - "body": { + "dynamic": "[true|false|strict]", + "_meta": { + "field": "value" + }, "properties": { "field1": { "type": "integer" @@ -56,8 +69,8 @@ Body: "type": "keyword" }, "field3": { - "type": "date", - "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" } } } @@ -68,14 +81,18 @@ Body: ## Arguments -* `collection`: collection name -* `index`: index name +* `collection`: name of the collection to update +* `index`: index that will host the new collection --- ## Body properties -* `properties`: object describing the data mapping to associate to the new collection, using [Elasticsearch mapping format](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping.html). +### Optional: + +* `dynamic`: [dynamic mapping policy]({{ site_base_path}}guide/1/essentials/database-mappings/#dynamic-mapping-policy) for new fields. Allowed values: `true` (default), `false`, `strict` +* `_meta`: [collection additional metadata]({{ site_base_path}}guide/1/essentials/database-mappings/#collection-metadata) stored next to the collection +* `properties`: object describing the data mapping to associate to the new collection, using [Elasticsearch types definitions format]({{ site_base_path}}guide/1/essentials/database-mappings/#properties-types-definition) --- diff --git a/src/guide/1/essentials/database-mappings/index.md b/src/guide/1/essentials/database-mappings/index.md new file mode 100644 index 000000000..222445655 --- /dev/null +++ b/src/guide/1/essentials/database-mappings/index.md @@ -0,0 +1,175 @@ +--- +layout: full.html.hbs +title: Define database mappings +order: 400 +--- + +# Database mappings + +With Elasticsearch, it is possible to define mappings for collections. These mappings allow you to configure the way Elasticsearch will handle these collections. + +There are 3 root fields for mapping configuration: + - [properties]({{ site_base_path}}guide/1/essentials/database-mappings/#properties-types-definition): collection types definition + - [dynamic]({{ site_base_path}}guide/1/essentials/database-mappings/#dynamic-mapping-policy): dynamic mapping policy against new fields + - [_meta]({{ site_base_path}}guide/1/essentials/database-mappings/#collection-metadata): collection metadata + +The following API methods can be used to modify these mappings: + - [collection:create]({{ site_base_path }}api/1/controller-collection/create/) + - [collection:updateMapping]({{ site_base_path }}api/1/controller-collection/update-mapping/) + +--- + +## Properties types definition + +The field type definitions that will be inserted in a collection allow Elasticsearch to index your data for future searches. + +Especially when searching on fields with special types such as `date` or `geo_shape`. + +
+Once a type has been defined for a field, it is not possible to modify it later. +
+ +Refer to the Elasticsearch documentation for an exhaustive list of available types: https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping-types.html + +### Example + +If I want the following document to be correctly indexed: +```javascript +{ + "category": "limousine", + "distance": 120990, + "position": { + "lat": 27.730400, + "lon": 85.328467 + }, + "driver": { + "name": "liia mhe ry" + } +} +``` + +The following mapping must first be defined: +```javascript +{ + "properties": { + "category": { "type": "keyword" }, + "distance": { "type": "integer" }, + "position": { "type": "geo_point" }, + "driver": { + "properties": { + "name": { "type": "keyword" } + } + } + } +} +``` + +This mapping is then passed in the body to the methods [collection:create]({{ site_base_path }}api/1/controller-collection/create/) or [collection:updateMapping]({{ site_base_path }}api/1/controller-collection/update-mapping/). + +```bash +# First create a collection yellow-taxi in the nyc-open-data index +curl -X PUT -d '{"properties":{"category":{"type":"keyword"},"distance":{"type":"integer"},"position":{"type":"geo_point"},"driver":{"properties":{"name":{"type":"keyword"}}}}}' -H "Content-Type: application/json" "http://localhost:7512/nyc-open-data/yellow-taxi?pretty" + +# Then create the desired document +curl -X POST -d '{"category":"limousine","distance":120990,"position":{"lat":27.7304,"lon":85.328467},"driver":{"name":"liia meh ry"}}' -H "Content-Type: application/json" "http://localhost:7512/nyc-open-data/yellow-taxi/_create?pretty" +``` + +
+Because of the way Elasticsearch manages collections, mappings are shared between indexes. +
+This means that if I have an index nyc-open-data, two collections yellow-taxi and green-taxi and a field name with type keyword in the collection yellow-taxi, then I can't have a field name with a different type in the collection green-taxi. +
+ +--- + +## Dynamic mapping policy + +For each collection, you can set the policy against new fields that are not referenced in the collection mapping by modifying the `dynamic` root field. + +The value of this configuration will change the way Elasticsearch manages the creation of new fields that are not declared in the collection mapping. + - `"true"`: Stores the document and updates the collection mapping with the inferred type + - `"false"`: Stores the document and does not update the collection mapping (fields are not indexed) + - `"strict"`: Rejects the document + +Refer to Elasticsearch documentation for more informations: https://www.elastic.co/guide/en/elasticsearch/guide/current/dynamic-mapping.html + +The default policy for new collections is `"true"` and is configurable in the [kuzzlerc]({{ site_base_path }}guide/1/essentials/configuration/) file under the key `services.db.dynamic`. + +
+We advise not to let Elasticsearch dynamically infer the type of new fields in production. +
+This can be a problem because then the mapping cannot be modified. +
+ +It is also possible to specify a different dynamic mapping policy for nested fields. This can be useful in imposing a strict policy on the collection while allowing the introduction of new fields in a specific location. + +### Example + +If you want a `strict` dynamic policy for your entire collection, you have to define it in root level but you can have a different policy for nested types: + +```javascript +{ + "dynamic": "strict" + "properties": { + "driver": { + "dynamic": "false" + "properties": // allow insertion of new fields in the driver nested field + } + } +} +``` +
+```bash +# Define a strict dynamic policy for the yellow-taxi collection +curl -X PUT -d '{ "dynamic": "strict" }' -H "Content-Type: application/json" "http://localhost:7512/nyc-open-data/yellow-taxi?pretty" + +# Try to create a document with a field that is not referenced in the mapping +curl -X POST -d '{"language":"nepali"}' -H "Content-Type: application/json" "http://localhost:7512/nyc-open-data/yellow-taxi/_create?pretty" + +# You should see an error with the following message: +# "mapping set to strict, dynamic introduction of [language] within [yellow-taxi] is not allowed" +``` + +--- + +## Collection metadata + +Elasticsearch allows the definition of metadata that is stored next to the collections in the root field `_meta`. +These metadata are ignored by Elasticsearch, they can contain any type of information specific to your application. + +
+Unlike the properties types definition, new collection metadata are not merged with the old one. +
+If you set the _meta field in your request, the old value will be overwritten. +
+ +Refer to Elasticsearch documentation for more informations: https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping-meta-field.html + +These metadata can be retrieved with the [collection:getMapping]({{ site_base_path }}api/1/controller-collection/get-mapping/) API method. + +### Example + +```javascript +{ + "_meta": { + "area": "Panipokhari" + } +} +``` +
+```bash +# Add collection metadata +curl -X PUT -d '{ "_meta": { "area": "Panipokhari" } }' -H "Content-Type: application/json" "http://localhost:7512/nyc-open-data/yellow-taxi/_mapping?pretty" + +# Retrieve it +curl -X GET -H "Content-Type: application/json" "http://localhost:7512/nyc-open-data/yellow-taxi/_mapping?pretty" +``` + +--- + +## What Now? + +* Learn to work with [Persistent Data]({{ site_base_path }}guide/1/essentials/persisted) +* Read our [Elasticsearch Cookbook]({{ site_base_path }}guide/1/elasticsearch) to learn more about how querying works in Kuzzle +* Use [document metadata]({{ site_base_path }}guide/1/essentials/document-metadata) to find or recover documents +* Keep track of data changes using [Real-time Notifications]({{ site_base_path }}guide/1/essentials/real-time) diff --git a/src/guide/1/essentials/persisted/index.md b/src/guide/1/essentials/persisted/index.md index d479f16e3..50ecd8914 100644 --- a/src/guide/1/essentials/persisted/index.md +++ b/src/guide/1/essentials/persisted/index.md @@ -84,7 +84,7 @@ You should receive the following response: } ``` -**Note:** we have just created a new collection without specifying any mappings. As a result, the database layer will automatically create a mapping that assigns a best guess data type to any new field it detects in input documents. Since these mappings cannot be changed once they are created, we strongly recommend that you [**create your own mappings**]({{ site_base_path }}guide/1/essentials/persisted/#mappings) as soon as the collection has been created. For the purpose of this tutorial, we will continue without defining our own mappings. +**Note:** we have just created a new collection without specifying any mappings. As a result, the database layer will automatically create a mapping that assigns a best guess data type to any new field it detects in input documents. Since these mappings cannot be changed once they are created, we strongly recommend that you [**create your own mappings**]({{ site_base_path }}guide/1/essentials/database-mappings) as soon as the collection has been created. For the purpose of this tutorial, we will continue without defining our own mappings. --- @@ -492,56 +492,6 @@ You should receive the following response (with your own `_id` values): --- -## Mappings - -Kuzzle uses Elasticsearch as a persistent document store, which uses mappings to assign a type to a document field. These mappings are attached to a `collection` (aka `type` in Elasticsearch terminology) and are automatically inferred from input documents if no mappings are preconfigured. - -If you want to control how Kuzzle interprets your documents, we recommend that you configure your own mappings using our mappings creation endpoint. - -Create a mapping by sending a `PUT` request to the `http://localhost:7512///_mapping` and setting the mapping in the request body. - -Use [this](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping.html) syntax when definng a mapping. For example, if we want to create a mapping that will define a field `birthday` as a `date` type, we would send the following JSON in the body: - -```json -{ - "properties": { - "birthday": { - "type": "date" - } - } -} -``` - -Let's try it: - -```bash - curl -X PUT -H "Content-Type: application/json" -d '{"properties":{"birthday":{"type": "date"}}}' http://localhost:7512/myindex/mycollection/_mapping -``` - -You should receive the following response: - -```json -{ - "requestId": "", - "status": 200, - "error": null, - "controller": "collection", - "action": "updateMapping", - "collection": "mycollection", - "index": "myindex", - "volatile": null, - "result": { - "acknowledged": true - } -} -``` - -Here we have now defined the type `date` for the field labeled `birthday` in our `mycollection` collection. Defining types in this way can be especially useful when dealing with specific types (`date`, `geo_shape`, etc.), full-text search, or complex data structures. - -Please note that the mappings of a collection cannot be updated once they are created, this is true whether you create the rules yourself using our API or whether Elasticsearch generates the rules automatically based on the input documents it processes. Because of this, you should almost always define mappings when you first create your collections and before creating any documents. - ---- - ## What Now? diff --git a/src/guide/1/essentials/plugins/index.md b/src/guide/1/essentials/plugins/index.md index 7723aa5c4..eaf865618 100644 --- a/src/guide/1/essentials/plugins/index.md +++ b/src/guide/1/essentials/plugins/index.md @@ -12,8 +12,8 @@ For example, imagine you are developing a mobile application that accesses a **t Kuzzle's **[Plugin Engine]({{ site_base_path }}plugins/1)** is a powerful feature that ensures that Kuzzle meets any project requirement: -* select from a set of prebuilt plugins (such as the [OAuth2 Authentication Plugin](https://github.com/kuzzleio/kuzzle-plugin-auth-passport-oauth) or the [MQTT Protocol](https://github.com/kuzzleio/protocol-mqtt)). -* [create your own plugin]({{ site_base_path }}plugins/1/essentials) to meet your specific requirements. +- select from a set of prebuilt plugins (such as the [OAuth2 Authentication Plugin](https://github.com/kuzzleio/kuzzle-plugin-auth-passport-oauth) or the [MQTT Protocol](https://github.com/kuzzleio/protocol-mqtt)). +- [create your own plugin]({{ site_base_path }}plugins/1/essentials) to meet your specific requirements. --- @@ -21,22 +21,22 @@ Kuzzle's **[Plugin Engine]({{ site_base_path }}plugins/1)** is a powerful featur Plugins are used to extend Kuzzle's functionalities. They are loaded into Kuzzle during startup and share its execution thread. A plugin can implement one or multiple of the following interfaces: -[Hooks]({{ site_base_path }}plugins/1/essentials/hooks): adds asynchronous listeners that perform operations triggered by data events. When a listened event occurs, the data is sent to the listeners and Kuzzle continues its process without waiting for the listener to complete. +[Hooks]({{ site_base_path }}plugins/1/hooks): adds asynchronous listeners that perform operations triggered by data events. When a listened event occurs, the data is sent to the listeners and Kuzzle continues its process without waiting for the listener to complete. - _Example - "Write a log to a third-party logging service every time a document is deleted"_. The [Logger Plugin](https://github.com/kuzzleio/kuzzle-plugin-logger) (shipped with Kuzzle) uses this feature to log all the data-related events. +_Example - "Write a log to a third-party logging service every time a document is deleted"_. The [Logger Plugin](https://github.com/kuzzleio/kuzzle-plugin-logger) (shipped with Kuzzle) uses this feature to log all the data-related events. -[Pipes]({{ site_base_path }}plugins/1/essentials/pipes): adds synchronous listeners that perform operations triggered by data events. When a listened event occurs, the data is passed synchronously to listeners, each modifying the input data and returning the result to the next listener. Kuzzle waits until the last listener completes and returns its data. If any listener returns an error, it will interrupt the Kuzzle lifecycle, and the thrown error will be used as a response by Kuzzle. +[Pipes]({{ site_base_path }}plugins/1/pipes): adds synchronous listeners that perform operations triggered by data events. When a listened event occurs, the data is passed synchronously to listeners, each modifying the input data and returning the result to the next listener. Kuzzle waits until the last listener completes and returns its data. If any listener returns an error, it will interrupt the Kuzzle lifecycle, and the thrown error will be used as a response by Kuzzle. - _Example - "Compare the ordered quantity with the available stock and return an error if the amount of ordered items exceeds the amount in stock"_. +_Example - "Compare the ordered quantity with the available stock and return an error if the amount of ordered items exceeds the amount in stock"_. -[Controllers]({{ site_base_path }}plugins/1/essentials/controllers): extends Kuzzle API. +[Controllers]({{ site_base_path }}plugins/1/controllers): extends Kuzzle API. - _Example - "Expose a `checkout` API endpoint that handles a third-party payment process"_. +_Example - "Expose a `checkout` API endpoint that handles a third-party payment process"_. [Strategies]({{ site_base_path }}plugins/1/essentials/strategies): add an authentication strategy to identify and authenticate users. - _Example - "Enable OAuth based authentication in Kuzzle"_ - Kuzzle ships with the [Local Strategy Plugin](https://github.com/kuzzleio/kuzzle-plugin-auth-passport-local) and thanks to PassportJS, more than 300 authentication strategies are readily available. +_Example - "Enable OAuth based authentication in Kuzzle"_ +Kuzzle ships with the [Local Strategy Plugin](https://github.com/kuzzleio/kuzzle-plugin-auth-passport-local) and thanks to PassportJS, more than 300 authentication strategies are readily available. ## Protocols @@ -61,10 +61,8 @@ Prior to loading the plugin into Kuzzle, you will need to load all of the plugin To demonstrate, we are going to install the [**Plugin Boilerplate**](https://github.com/kuzzleio/kuzzle-core-plugin-boilerplate), a plugin example that uses all features available to a plugin. - Go to the Kuzzle installation folder and type: - ```bash # Open plugins/available folder cd plugins/available @@ -105,13 +103,8 @@ Once Kuzzle has restarted, check the server information at `http://localhost:751 "document:beforeUpdate", "core:overload" ], - "pipes": [ - "document:beforeCreate", - "realtime:beforePublish" - ], - "controllers": [ - "kuzzle-core-plugin-boilerplate/myNewController" - ], + "pipes": ["document:beforeCreate", "realtime:beforePublish"], + "controllers": ["kuzzle-core-plugin-boilerplate/myNewController"], "routes": [ { "verb": "get", @@ -126,9 +119,7 @@ Once Kuzzle has restarted, check the server information at `http://localhost:751 "action": "myNewAction" } ], - "strategies": [ - "dummy" - ] + "strategies": ["dummy"] } } } @@ -138,13 +129,13 @@ Once Kuzzle has restarted, check the server information at `http://localhost:751 ``` Note that the plugin description above contains a property for each plugin component: + - `hooks` asynchronous operations that depend on data-related events - `pipes` synchronous operations that depend on data-related events - `controllers` list of exposed actions in the API - `routes` list of exposed actions in the **REST** API - `strategies` list of exposed authentication strategies - --- ## Installing protocols @@ -179,6 +170,7 @@ ln -s ../available/protocol-mqtt . To get more insight into how plugins work, please refer to the [Plugin Reference]({{ site_base_path }}plugins/1). Here is a list of official plugins: + - [**kuzzle-plugin-auth-passport-local**](https://github.com/kuzzleio/kuzzle-plugin-auth-passport-local): authentication Plugin shipped with Kuzzle - [**kuzzle-plugin-logger**](https://github.com/kuzzleio/kuzzle-plugin-logger): plugin shipped with Kuzzle - [**kuzzle-plugin-auth-passport-oauth**](https://github.com/kuzzleio/kuzzle-plugin-auth-passport-oauth): authentication plugin diff --git a/src/plugins/1/accessors/trigger/index.md b/src/plugins/1/accessors/trigger/index.md index 157b4b3d7..8d92c562d 100644 --- a/src/plugins/1/accessors/trigger/index.md +++ b/src/plugins/1/accessors/trigger/index.md @@ -9,23 +9,22 @@ title: trigger Triggers a custom event. -This allows interactions with other plugins using [hooks]({{ site_base_path }}plugins/1/essentials/hooks/) or [pipes]({{ site_base_path }}plugins/1/essentials/pipes/). +This allows interactions with other plugins using [hooks]({{ site_base_path }}plugins/1/hooks/) or [pipes]({{ site_base_path }}plugins/1/pipes/). ## Arguments ```js -trigger(event, [payload]) +trigger(event, [payload]); ```
-| Arguments | Type | Description | -|-----------|------|-------------| -| `event` |
string
| Custom event name | -| `payload` |
object
| Event payload | +| Arguments | Type | Description | +| --------- | ----------------- | ----------------- | +| `event` |
string
| Custom event name | +| `payload` |
object
| Event payload | - -**Note:** the triggered event is renamed using the following format:
`plugin-:`. +**Note:** the triggered event is renamed using the following format:
`plugin-:`. ## Example @@ -37,13 +36,13 @@ context.accessors.trigger('someEvent', { // Listening plugin class ListeningPlugin { - constructor () { + constructor() { this.hooks = { 'plugin-some-plugin:someEvent': 'someEventListener' }; } - someEventListener (payload) { + someEventListener(payload) { this.doSomething(payload); } } diff --git a/src/plugins/1/essentials/controllers/index.md b/src/plugins/1/controllers/Documentation/index.md similarity index 82% rename from src/plugins/1/essentials/controllers/index.md rename to src/plugins/1/controllers/Documentation/index.md index f75639e5f..2c68c049f 100644 --- a/src/plugins/1/essentials/controllers/index.md +++ b/src/plugins/1/controllers/Documentation/index.md @@ -1,6 +1,6 @@ --- layout: full.html.hbs -title: Controllers +title: Documentation order: 400 --- @@ -8,7 +8,7 @@ order: 400 Kuzzle's API is divided into controllers, each exposing executable actions (see [API reference]({{ site_base_path }}api/1/essentials/query-syntax)). -Plugins can extend Kuzzle's API by adding new controllers to it. +Plugins can extend Kuzzle's API by adding new controllers to it. [Security access]({{ site_base_path }}guide/1/essentials/security/) to plugin controllers must be given (or denied), using the exact same way as with native API controllers. @@ -21,7 +21,7 @@ To avoid naming conflicts, Kuzzle prefixes plugin controllers names with the plu ### HTTP ```http -URL: http://:/_plugin/// +URL: http://:/_plugin/// Method: ``` @@ -53,16 +53,17 @@ Kuzzle normalizes [queries]({{ site_base_path }}api/1/essentials/query-syntax) i Quick summary of how queries are normalized: -* HTTP: - * dynamic arguments provided in the URL, and query string arguments are stored in `request.input.args` - * the body content is made available in `request.input.body` - * if the URL contains an `index`, a `collection` or a `_id` argument, it will be stored in `request.input.resource` - * request headers can be found in `request.context.connection.misc.headers` +- HTTP: -* Other protocols: - * the `body` property is stored in `request.input.body` - * these root properties are available in `request.input.resource`: `index`, `collection`, `_id` - * any other properties at the root of the query object will be stored in `request.input.args` + - dynamic arguments provided in the URL, and query string arguments are stored in `request.input.args` + - the body content is made available in `request.input.body` + - if the URL contains an `index`, a `collection` or a `_id` argument, it will be stored in `request.input.resource` + - request headers can be found in `request.context.connection.misc.headers` + +- Other protocols: + - the `body` property is stored in `request.input.body` + - these root properties are available in `request.input.resource`: `index`, `collection`, `_id` + - any other properties at the root of the query object will be stored in `request.input.args` --- @@ -78,7 +79,7 @@ Read more about these automatic controller events [here]({{ site_base_path }}plu ```javascript module.exports = class ControllerPlugin { - constructor () { + constructor() { /* Adds a new "newController" controller to Kuzzle's API. @@ -128,8 +129,18 @@ module.exports = class ControllerPlugin { property */ this.routes = [ - {verb: 'get', url: '/foo/:name', controller: 'newController', action: 'myAction'}, - {verb: 'post', url: '/bar', controller: 'newController', action: 'myOtherAction'} + { + verb: 'get', + url: '/foo/:name', + controller: 'newController', + action: 'myAction' + }, + { + verb: 'post', + url: '/bar', + controller: 'newController', + action: 'myOtherAction' + } ]; } @@ -137,7 +148,7 @@ module.exports = class ControllerPlugin { Required plugin initialization function (see the "Plugin prerequisites" section) */ - init (customConfig, context) { + init(customConfig, context) { // plugin initialization } @@ -148,17 +159,20 @@ module.exports = class ControllerPlugin { This result can be of any JS type (scalar, object, array), and will be used to build a response to send to the requesting client */ - actionFunction (request) { + actionFunction(request) { // do action // optional: set network specific headers if (request.context.protocol === 'http') { // expires in 1h - request.response.setHeader('expires', new Date(Date.now() + 3600000).toUTCString()); + request.response.setHeader( + 'expires', + new Date(Date.now() + 3600000).toUTCString() + ); } // Resolve with the result content. For instance: - return Promise.resolve({acknowledge: true}); + return Promise.resolve({ acknowledge: true }); } /* @@ -168,9 +182,9 @@ module.exports = class ControllerPlugin { This result can be of any JS type (scalar, object, array), and will be used to build a response to send to the requesting client */ - otherActionFunction (request) { + otherActionFunction(request) { // do action return Promise.resolve(/* result content */); } -} +}; ``` diff --git a/src/plugins/1/controllers/index.md b/src/plugins/1/controllers/index.md new file mode 100644 index 000000000..478804e82 --- /dev/null +++ b/src/plugins/1/controllers/index.md @@ -0,0 +1,5 @@ +--- +layout: full.html.hbs +title: Controllers +order: 4 +--- diff --git a/src/plugins/1/essentials/getting-started/index.md b/src/plugins/1/essentials/getting-started/index.md index 34257dc28..a66c74e6c 100644 --- a/src/plugins/1/essentials/getting-started/index.md +++ b/src/plugins/1/essentials/getting-started/index.md @@ -1,31 +1,17 @@ --- layout: full.html.hbs -title: Getting Started +title: Getting started description: how to create a custom plugin -order: 0 +order: 1 --- -# Getting Started - -Kuzzle can be customized and extended using plugins. - -This chapter explains how to install and configure a plugin. The other chapters in this section cover the four plugin interfaces exposed by Kuzzle: - -* [Hooks](../hooks) -* [Pipes](../pipes) -* [Controllers](../controllers) -* [Authentication Strategies](../strategies) - -A single plugin can implement as many of those interfaces as necessary. - ---- - -## Plugin Boilerplate +# Getting started The best way to start developing a plugin is to use a boilerplate. We provide a boilerplate that contain a Kuzzle stack that reloads itself whenever a plugin change is detected, making it a handy tool for plugin development. - - [kuzzle-core-plugin-boilerplate](https://github.com/kuzzleio/kuzzle-core-plugin-boilerplate) + +- [kuzzle-core-plugin-boilerplate](https://github.com/kuzzleio/kuzzle-core-plugin-boilerplate) Clone this repository to start developing a Kuzzle plugin: @@ -34,87 +20,27 @@ git clone https://github.com/kuzzleio/kuzzle-core-plugin-boilerplate cd kuzzle-core-plugin-boilerplate docker-compose -f docker/docker-compose.yml up // Kuzzle stack with the plugin is ready -// Edit the file lib/index.js, +// Edit the file lib/index.js, // the Kuzzle stack will automaticaly restart to include your modifications ``` -## Prerequisites - -### Location - -Plugins are subdirectories that must be put at the following location: `/plugins/enabled`. +The provided `docker-compose.yml` file launches a Kuzzle stack with the `pm2` module, with the following features: -The recommended way to install a plugin is to put it in `plugins/available`, and then link it to the `plugins/enabled` directory. +- Automated Kuzzle restart every time a change is detected in the plugin code +- Configurable through the parameters set in that `pm2.json` file -### Node.js modules +The main Plugin class is defined in the `index.js`. You can start edit it adding: -Kuzzle loads plugins as [Node.js modules](https://nodejs.org/dist/latest-v8.x/docs/api/modules.html). +- [Hooks]({{ site_base_path }}plugins/1/hooks/) +- [Pipes]({{ site_base_path }}plugins/1/pipes/) +- [Controllers]({{ site_base_path }}plugins/1/controllers/) +- [Authentication Strategies]({{ site_base_path }}plugins/1/strategies/overview/) -This means that a plugin directory must contain either: - -* an `index.js` file - -and/or: - -* a valid [package.json](https://docs.npmjs.com/files/package.json) file. If the plugin's entrypoint is not the root `index.js` file, then the [main](https://docs.npmjs.com/files/package.json#main) property must be filled - -### manifest.json - -Kuzzle needs a few information to make your plugin work properly. These information must be provided in a `manifest.json` file, in the plugin directory. - -The following properties can be defined in this `manifest.json` file: - -* `name` (**required**): plugin unique identifier. Names can only contain lowercase letters, numbers, hyphens and underscores. -* `kuzzleVersion`: a non-empty string describing a [semver range](https://www.npmjs.com/package/semver#ranges), limiting the range of Kuzzle versions supported by this plugin. If not set, a warning is displayed on the console, and Kuzzle assumes that the plugin is only compatible with Kuzzle v1.x - -{{{deprecated "1.5.0"}}} Kuzzle still allows plugins to be loaded without a manifest.json file, for backward compatibility reasons, falling back to the package.json file to retrieve the plugin's name. This will change in next major releases of Kuzzle. - ---- +We need to provide the `configuration` and the `context` to plugins. In that purpose, plugins must have an `init` function which will have them as parameters : this `init` function is the very first one to be called by Kuzzle and is mandatory to start a plugin. You can now write your own functions and your own routes as described inside the `index.js`. You can also write unit tests : see `steps.js`. -## init function - -Plugins must expose an `init` function. If it is missing, Kuzzle fails to load the plugin and aborts its start sequence. - -The `init` method is called once during startup, and it is used to initialize the plugin. - -### Arguments - -```js -init (config, context) -``` - -
- -| Arguments | Type | Description | -|-----------|------|-------------| -| `config` |
object
| Contains the custom plugin configuration (see the [configuration](#configuration-default) chapter) | -| `context` |
object
| The plugin context, exposing various accessors, constructors, and helpers. The other sections of this documentation detail the interfaces made available by this object | - -### Return - -The `init` function can optionally return a promise. If it does, Kuzzle waits for the promise to be resolved before continuing its own initialization. - -If a promise is returned, it must be resolved within the configured timeout (see `plugins.common.initTimeout` in Kuzzle's [configuration]({{ site_base_path }}guide/1/essentials/configuration/)) - -If a promise is returned and rejected, or if the `init` function throws an error, Kuzzle aborts its start sequence and shuts down. - ---- - -## Configuration - -When Kuzzle calls the plugin `init` method, it passes the plugin's custom configuration to it. - -Custom configuration parameters are specified for each plugin in the `plugins` object of the Kuzzle [configuration file]({{ site_base_path }}guide/1/essentials/configuration). - -For example: - -```json -{ - "plugins": { - "foobar-plugin": { - "option_1": "option_value", - "option_2": "option_value" - } - } -} -``` +
+You can find more information about the init function here. +
+
+You have now everything you need to start writing your own Kuzzle plugin. +
diff --git a/src/plugins/1/essentials/index.md b/src/plugins/1/essentials/index.md index e04802e26..8c1f9bc78 100644 --- a/src/plugins/1/essentials/index.md +++ b/src/plugins/1/essentials/index.md @@ -1,7 +1,7 @@ --- layout: full.html.hbs title: Essentials -description: Introduction to the plugin engine -order: 0 separator: Plugins +description: how to create a custom plugin +order: 0 --- diff --git a/src/plugins/1/essentials/introduction/index.md b/src/plugins/1/essentials/introduction/index.md new file mode 100644 index 000000000..01f3c1217 --- /dev/null +++ b/src/plugins/1/essentials/introduction/index.md @@ -0,0 +1,19 @@ +--- +layout: full.html.hbs +title: Introduction +description: how to create a custom plugin +order: 0 +--- + +# Introduction + +Kuzzle can be customized and extended using plugins. + +This page explains how to install and configure a plugin. The other pages cover the four plugin interfaces exposed by Kuzzle: + +- [Hooks]({{ site_base_path }}plugins/1/hooks/) +- [Pipes]({{ site_base_path }}plugins/1/pipes/) +- [Controllers]({{ site_base_path }}plugins/1/controllers/) +- [Authentication Strategies]({{ site_base_path }}plugins/1/strategies/overview/) + +A single plugin can implement as many of those interfaces as necessary. diff --git a/src/plugins/1/essentials/strategies/index.md b/src/plugins/1/essentials/strategies/index.md deleted file mode 100644 index 12aeac08e..000000000 --- a/src/plugins/1/essentials/strategies/index.md +++ /dev/null @@ -1,443 +0,0 @@ ---- -layout: full.html.hbs -title: Strategies -order: 500 ---- - -# Strategies - -Plugins can add new authentication strategies to Kuzzle. -For example, our official [OAUTH2 Authentication plugin](https://github.com/kuzzleio/kuzzle-plugin-auth-passport-oauth) adds OAUTH2 support to Kuzzle. - -All authentication strategies supported by [Passport.js](http://passportjs.org/) can be integrated to Kuzzle. - ---- - -## Registering authentication strategies - -[Passport.js](http://passportjs.org) provides a wide range of authentication strategies. -Custom authentication strategies can also be implemented by subclassing the abstract [Passport Strategy](https://github.com/jaredhanson/passport-strategy) class. - -To register strategies to Kuzzle, a `authenticators` object property must be exposed by the plugin, for instance: - -```js -this.authenticators = { - Local: require('passport-local'), - Oauth2: require('passport-oauth2') -}; -``` - ---- - -## Credentials security - -User credentials are very sensitive data, and these must be properly isolated to prevent security vulnerabilities. -To do so, Kuzzle guarantees that it never interprets, modifies, or stores credentials information. - -Instead, Kuzzle: - -* provides a global user unique identifier (referred from now on as the user's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid)), giving the possibility to a user to authenticate with multiple strategies -* entrusts implemented strategies with credentials protection, validation, verification and storage - ---- - -## Managing credentials - -There are two ways of interfacing credentials management: - -* statically, by exposing a `strategies` object -* dynamically, by using the dedicated [strategy accessors]({{ site_base_path }}plugins/1/accessors/strategies) - -Whether strategies are added statically or dynamically, the `strategies` object must expose the following properties: - -| Arguments | Type | Description | -|-----------|------|-------------| -| `config` |
object
| Authentication strategy configuration | -| `methods` |
object
| List of exposed methods | - -### config - -The `config` part of the `strategies` object can contain the following properties: - -| Arguments | Type | Description | -|-----------|------|-------------| -| `authenticator` |
string
| One of the exposed [authenticators]({{ site_base_path }}plugins/1/essentials/strategies/#registering-authentication-strategies-default) name | -| `constructor` |
object
| {{{deprecated "1.4.0"}}} (use the `authenticator` property instead)
The constructor of the Passport.js strategy. Does not support [dynamic strategy registration]({{ site_base_path }}plugins/1/accessors/strategies) | -| `authenticateOptions` |
object
| (optional) Additional options to be provided to the Passport's [authenticate method](http://passportjs.org/docs/authenticate) -| `fields` |
string[]
| (optional) The list of accepted field names by the strategy credentials.
The list is informative only, meant to be used by the [getAllCredentialFields]({{ site_base_path }}api/1/controller-security/get-all-credential-fields/) and the [getCredentialFields]({{ site_base_path }}api/1/controller-security/get-credential-fields) API methods -| `strategyOptions` |
object
| (optional) Options provided to the Passport.js strategy constructor | - -### methods - -The `methods` part of the `strategies` object can contain the following properties: - -| Arguments | Type | Description | -|-----------|------|-------------| -| `create` |
string
| The name of the exposed [create]({{ site_base_path }}plugins/1/essentials/strategies/#create-default) function | -| `delete` |
string
| The name of the exposed [delete]({{ site_base_path }}plugins/1/essentials/strategies/#delete-default) function | -| `exists` |
string
| The name of the exposed [exists]({{ site_base_path }}plugins/1/essentials/strategies/#exists-default) function | -| `update` |
string
| The name of the exposed [update]({{ site_base_path }}plugins/1/essentials/strategies/#update-default) function | -| `validate` |
string
| The name of the exposed [validate]({{ site_base_path }}plugins/1/essentials/strategies/#update-default) function | -| `verify` |
string
| The name of the exposed [verify]({{ site_base_path }}plugins/1/essentials/strategies/#verify-default) function | -| `afterRegister` |
string
| (optional) The name of the exposed [afterRegister]({{ site_base_path }}plugins/1/essentials/strategies/#optional-afterregister-default) function | -| `getById` |
string
| (optional) The name of the exposed [getById]({{ site_base_path }}plugins/1/essentials/strategies/#optional-getbyid-default) function | -| `getInfo` |
string
| (optional) The name of the exposed [getInfo]({{ site_base_path }}plugins/1/essentials/strategies/#optional-getinfo-default) function | - -Even though each strategy must declare its own set of properties, the same strategy method can be used by multiple strategies. - ---- - -## create - -The `create` function adds credentials to a user. - -For security reasons, plugins are entirely responsible of how credentials are managed, storage included: Kuzzle does not read, modify, or store credentials. - -If needed, Kuzzle exposes a secure and isolated storage space for each plugin. It can be accessed using the [Repository]({{ site_base_path }}plugins/1/constructors/repository) constructor. - -### Arguments - -```js -create(request, credentials, kuid, strategy) -``` -
- -| Arguments | Type | Description | -|-----------|------|-------------| -| `request` |
Request
| API request asking for the credentials creation | -| `credentials` |
object
| New credentials to create, already validated by this strategy's [validate](#validate) function | -| `kuid` |
string
| User's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid) | -| `strategy` |
string
| Authentication strategy used by these credentials | - -### Returned value - -The `create` function must return a promise, resolving to an object. The content of that object depends on this authentication strategy; usually a feedback about the created credentials is expected. That object can be left empty. - -
The object resolved by the promise is directly forwarded to the originating user. For security reasons, it must only contain non sensitive information.
- ---- - -## delete - -The `delete` function deletes a user's credentials. - -### Arguments - -```js -delete(request, kuid, strategy) -``` -
- -| Arguments | Type | Description | -|-----------|------|-------------| -| `request` |
Request
| API request asking for the credentials deletion | -| `kuid` |
string
| User's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid) | -| `strategy` |
string
| Authentication strategy name | - -### Returned value - -The `delete` function must return a promise. The resolved value is not used. - ---- - -## exists - -The `exists` function checks whether a user is known to the authentication strategy. - -### Arguments - -```js -exists(request, kuid, strategy) -``` - -
- -| Arguments | Type | Description | -|-----------|------|-------------| -| `request` |
Request
| Source API request | -| `kuid` |
string
| User's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid) | -| `strategy` |
string
| Authentication strategy name | - -### Returned value - -The `exists` function must return a promise, resolving to a boolean representing the result of the user existence check. - ---- - -## update - -The `update` function updates a user's credentials. - -### Arguments - -```js -update(request, credentials, kuid, strategy) -``` - -
- -| Arguments | Type | Description | -|-----------|------|-------------| -| `request` |
Request
| Source API request | -| `credentials` |
object
| Updated credentials.
Those are already validated by this strategy's [validate](#validate) function | -| `kuid` |
string
| User's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid) | -| `strategy` |
string
| Authentication strategy name | - -### Returned value - -The `update` function must return a promise, resolving to an object. The content of that object depends on this authentication strategy; usually a feedback about the updated credentials is expected. That object can be left empty. - -
The object resolved by the promise is directly forwarded to the originating user. For security reasons, it must only contain non sensitive information.
- ---- - -## validate - -The `validate` function verifies that credentials are well-formed. - -### Arguments - -```js -validate(request, credentials, kuid, strategy, isUpdate) -``` - -
- -| Arguments | Type | Description | -|-----------|------|-------------| -| `request` |
Request
| Source API request | -| `credentials` |
object
| Credentials to validate | -| `kuid` |
string
| User's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid) | -| `strategy` |
string
| Authentication strategy name | -| `isUpdate` |
boolean
| Tells whether the request is a credentials update. In the case of an update, the `credentials` object may only contain changes to be applied, instead of a complete credentials description | - -### Returned value - -The function `validate` must return a promise. The resolved value, if there is one, is ignored. - ---- - -## verify - -The [verify](http://passportjs.org/docs/configure) function authenticates a user. - -The number of arguments taken by the `verify` function depends on the authentication strategy. -For instance, a `local` authentication strategy requires that the `verify` function validates both a user name and a password, so these two arguments will have to be provided to the `verify` function. - -### Arguments - -```js -verify(payload, ...) -``` -
- -| Arguments | Type | Description | -|-----------|------|-------------| -| `payload` |
object
| Login request made to passport | -| `...` |
*
| Additional arguments; depends on the authentication strategy | - -#### payload - -The `payload` object has the following properties: - -
- -| Properties | Type | Description | -|-----------|------|-------------| -| `original` |
Request
| Source API login request | -| `query` |
object
| Direct link to `original.input.args`, containing the optional request arguments | -| `body` |
object
| Direct link to `original.input.body`, containing the request body content | - -### Returned value - -The `verify` function must return a promise, resolving to an object with the following properties: - -
- -| Properties | Type | Description | -|-----------|------|-------------| -| `kuid` |
string
| If the authentication succeeds, this property must be set to the user's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid). Otherwise, this must be set to `null` | -| `message` |
string
| If `kuid` is set to `null` (authentication failed), this optional property can be set with a rejection reason | - -
A failed authentication is not an error. The returned promise should only be rejected if an actual error occurs.
- ---- - -## (optional) afterRegister - -The `afterRegister` function is called when the Passport.js strategy is instantiated by Kuzzle. - -### Arguments - -```js -afterRegister(strategyInstance) -``` - -
- -| Arguments | Type | Description | -|-----------|------|-------------| -| `strategyInstance` |
object
| The Passport.js strategy instance | - ---- - -## (optional) getById - -The `getById` function returns credentials information using the authentication strategy's user identifier (which may not be the [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid)). - -If this function is not implemented, an empty object is returned by Kuzzle instead. - -
The returned information can be forwarded to users. For security reasons, it must only contain non sensitive information.
- -### Arguments - -```js -getById(request, id, strategy) -``` - -
- -| Arguments | Type | Description | -|-----------|------|-------------| -| `request` |
Request
| The API request asking for credentials information | -| `id` |
string
| Strategy's user identifier | -| `strategy` |
string
| Authentication strategy name | - -### Returned value - -The `getById` function must return a promise, resolving to an object containing credentials information. It can be left empty. - ---- - -## (optional) getInfo - -The `getInfo` function returns information about a user's credentials. - -If this function is not implemented, an empty object is returned by Kuzzle instead. - -
The returned information can be forwarded to users. For security reasons, it must only contain non sensitive information.
- -### Arguments - -```js -getInfo(request, kuid, strategy) -``` - -
- -| Arguments | Type | Description | -|-----------|------|-------------| -| `request` |
Request
| The API request asking for credentials information | -| `kuid` |
string
| User's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid) | -| `strategy` |
string
| Authentication strategy name | - -### Returned value - -The `getInfo` function must return a promise, resolving to an object containing credentials information. It can be left empty. - ---- - -## Example - -```javascript -module.exports = class AuthenticationPlugin { - constructor() {} - - /** - Required plugin initialization function - (see the "Plugin prerequisites" section) - */ - init (customConfig, context) { - this.authenticators = { - StrategyConstructor: require('some-passport-strategy') - }; - - this.strategies = { - '': { - config: { - // Must be declared in this.authenticators - authenticator: 'StrategyConstructor', - - // The list of fields that have to be provided in the credentials - fields: ['login', 'password'] - }, - methods: { - create: 'create', - delete: 'delete', - exists: 'exists', - update: 'update', - validate: 'validate', - verify: 'verify' - } - } - }; - } - - /** - * Stores the provided credentials - * Must keep a link between the persisted credentials - * and the kuid - */ - create (request, credentials, kuid) { - // store credentials - return Promise.resolve({/* non sensitive credentials info */}); - } - - /** - * Removes the user's stored credentials from - * the plugin persistence layer - */ - delete (request, kuid) { - // remove credentials - return Promise.resolve(); - } - - /** - * Checks if user's credentials exist in the persistence layer - */ - exists (request, kuid) { - // check credentials existence - return Promise.resolve(/* boolean value */); - } - - /** - * Updates the user's credentials information in the - * persistence layer - * - * @param {KuzzleRequest} request - * @param {object} credentials - * @param {string} kuid - * @returns {Promise} - */ - update (request, credentials, kuid) { - // update credentials - return Promise.resolve(/* non sensitive credentials info */); - } - - /** - * Validates credentials against the strategy rules - * (required fields, password strength, username uniqueness, ...) - */ - validate (request, credentials, kuid, strategy, isUpdate) { - // validate credentials - return Promise.resolve(/* true|false */); - } - - /** - * Returns an object with the authenticated user id if successful, - * and a reason if the authentication fails - */ - verify (request, ...credentials) { - const kuid = /* authentification */; - - if (kuid) { - return Promise.resolve({kuid}); - } - - return Promise.resolve({ - kuid: null, - message: 'Login failed - You shall not pass! Reason: ...' - }); - } -} -``` diff --git a/src/plugins/1/events/index.md b/src/plugins/1/events/index.md index c21b92eb8..641ef4b97 100644 --- a/src/plugins/1/events/index.md +++ b/src/plugins/1/events/index.md @@ -1,5 +1,5 @@ --- layout: full.html.hbs title: Events -order: 100 +order: 6 --- diff --git a/src/plugins/1/events/intro/index.md b/src/plugins/1/events/intro/index.md index 11ee17ca5..387dd9c06 100644 --- a/src/plugins/1/events/intro/index.md +++ b/src/plugins/1/events/intro/index.md @@ -1,6 +1,6 @@ --- layout: full.html.hbs -title: "Getting Started" +title: 'Getting Started' description: Exhaustive events list order: 0 --- @@ -11,4 +11,4 @@ Kuzzle emits numerous events, especially for API requests. Plugins can [listen]({{ site_base_path }}plugins/1/essentials/) to events. -And if a plugin adds new API [controllers]({{ site_base_path }}plugins/1/essentials/controllers), then Kuzzle automatically triggers [dedicated events]({{ site_base_path }}plugins/1/events/plugin-events). +And if a plugin adds new API [controllers]({{ site_base_path }}plugins/1/controllers), then Kuzzle automatically triggers [dedicated events]({{ site_base_path }}plugins/1/events/plugin-events). diff --git a/src/plugins/1/essentials/hooks/index.md b/src/plugins/1/hooks/Documentation/index.md similarity index 73% rename from src/plugins/1/essentials/hooks/index.md rename to src/plugins/1/hooks/Documentation/index.md index 5f1fc37d1..6fdf8e44d 100644 --- a/src/plugins/1/essentials/hooks/index.md +++ b/src/plugins/1/hooks/Documentation/index.md @@ -1,6 +1,6 @@ --- layout: full.html.hbs -title: Hooks +title: Documentation order: 200 --- @@ -29,30 +29,30 @@ this.hooks = { ```javascript module.exports = class HookPlugin { - constructor () {} + constructor() {} /* Required plugin initialization function (see the "Plugin prerequisites" section) */ - init (customConfig, context) { + init(customConfig, context) { /* - Calls the plugin function "myFunction" when the Kuzzle event - "document:afterCreate" is triggered after a successful - document creation + Calls the plugin functions when the Kuzzle events + are */ this.hooks = { - 'document:afterCreate': (...args) => this.myFunction(...args) + 'core:kuzzleStart': this.myFunctionOnStart.bind(this), + 'document:afterCreate': this.myFunctionOnCreate.bind(this) }; } /* - Called whenever the "document:afterCreate" event - is triggered - */ - myFunction (request, event) { + Called whenever the "document:afterCreate" event + is triggered + */ + myFunctionOnCreate(request, event) { console.log(`Event ${event} triggered`); console.log(`Document created: ${request.result._id}`); } -} +}; ``` diff --git a/src/plugins/1/hooks/index.md b/src/plugins/1/hooks/index.md new file mode 100644 index 000000000..686a01ec6 --- /dev/null +++ b/src/plugins/1/hooks/index.md @@ -0,0 +1,5 @@ +--- +layout: full.html.hbs +title: Hooks +order: 2 +--- diff --git a/src/plugins/1/index.md b/src/plugins/1/index.md index 98103cd96..e7ca92451 100644 --- a/src/plugins/1/index.md +++ b/src/plugins/1/index.md @@ -1,7 +1,4 @@ --- layout: full.html.hbs title: Plugins -order: 600 -description: Learn how to enhance Kuzzle -icon: fa-puzzle-piece --- diff --git a/src/plugins/1/manual-setup/config/index.md b/src/plugins/1/manual-setup/config/index.md new file mode 100644 index 000000000..e29a54438 --- /dev/null +++ b/src/plugins/1/manual-setup/config/index.md @@ -0,0 +1,25 @@ +--- +layout: full.html.hbs +title: Configuration +description: how to create a custom plugin +order: 1 +--- + +# Configuration + +When Kuzzle calls the plugin `init` method, it passes the plugin's custom configuration to it. + +Custom configuration parameters are specified for each plugin in the `plugins` object of the Kuzzle [configuration file]({{ site_base_path }}guide/1/essentials/configuration). + +For example: + +```json +{ + "plugins": { + "foobar-plugin": { + "option_1": "option_value", + "option_2": "option_value" + } + } +} +``` diff --git a/src/plugins/1/manual-setup/index.md b/src/plugins/1/manual-setup/index.md new file mode 100644 index 000000000..5147e5342 --- /dev/null +++ b/src/plugins/1/manual-setup/index.md @@ -0,0 +1,6 @@ +--- +layout: full.html.hbs +title: Manual Setup +description: how to create a custom plugin +order: 1 +--- diff --git a/src/plugins/1/manual-setup/init-function/index.md b/src/plugins/1/manual-setup/init-function/index.md new file mode 100644 index 000000000..2c846c84e --- /dev/null +++ b/src/plugins/1/manual-setup/init-function/index.md @@ -0,0 +1,33 @@ +--- +layout: full.html.hbs +title: init function +description: how to create a custom plugin +order: 2 +--- + +# init function + +Plugins must expose an `init` function. If it is missing, Kuzzle fails to load the plugin and aborts its start sequence. + +The `init` method is called once during startup, and it is used to initialize the plugin. + +## Arguments + +```js +init(config, context); +``` + +
+ +| Arguments | Type | Description | +| --------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `config` |
object
| Contains the custom plugin configuration (see the [configuration](#configuration-default) chapter) | +| `context` |
object
| The plugin context, exposing various accessors, constructors, and helpers. The other sections of this documentation detail the interfaces made available by this object | + +## Return + +The `init` function can optionally return a promise. If it does, Kuzzle waits for the promise to be resolved before continuing its own initialization. + +If a promise is returned, it must be resolved within the configured timeout (see `plugins.common.initTimeout` in Kuzzle's [configuration]({{ site_base_path }}guide/1/essentials/configuration/)) + +If a promise is returned and rejected, or if the `init` function throws an error, Kuzzle aborts its start sequence and shuts down. diff --git a/src/plugins/1/manual-setup/prerequisites/index.md b/src/plugins/1/manual-setup/prerequisites/index.md new file mode 100644 index 000000000..ebcd355ee --- /dev/null +++ b/src/plugins/1/manual-setup/prerequisites/index.md @@ -0,0 +1,37 @@ +--- +layout: full.html.hbs +title: Prerequisites +description: how to create a custom plugin +order: 0 +--- + +# Prerequisites + +## Location + +Plugins are subdirectories that must be put at the following location: `/plugins/enabled`. + +The recommended way to install a plugin is to put it in `plugins/available`, and then link it to the `plugins/enabled` directory. + +## Node.js modules + +Kuzzle loads plugins as [Node.js modules](https://nodejs.org/dist/latest-v8.x/docs/api/modules.html). + +This means that a plugin directory must contain either: + +- an `index.js` file + +and/or: + +- a valid [package.json](https://docs.npmjs.com/files/package.json) file. If the plugin's entrypoint is not the root `index.js` file, then the [main](https://docs.npmjs.com/files/package.json#main) property must be filled + +## manifest.json + +Kuzzle needs a few information to make your plugin work properly. These information must be provided in a `manifest.json` file, in the plugin directory. + +The following properties can be defined in this `manifest.json` file: + +- `name` (**required**): plugin unique identifier. Names can only contain lowercase letters, numbers, hyphens and underscores. +- `kuzzleVersion`: a non-empty string describing a [semver range](https://www.npmjs.com/package/semver#ranges), limiting the range of Kuzzle versions supported by this plugin. If not set, a warning is displayed on the console, and Kuzzle assumes that the plugin is only compatible with Kuzzle v1.x + +{{{deprecated "1.5.0"}}} Kuzzle still allows plugins to be loaded without a manifest.json file, for backward compatibility reasons, falling back to the package.json file to retrieve the plugin's name. This will change in next major releases of Kuzzle. diff --git a/src/plugins/1/essentials/pipes/index.md b/src/plugins/1/pipes/Documentation/index.md similarity index 79% rename from src/plugins/1/essentials/pipes/index.md rename to src/plugins/1/pipes/Documentation/index.md index 2d130404f..e2e8dacae 100644 --- a/src/plugins/1/essentials/pipes/index.md +++ b/src/plugins/1/pipes/Documentation/index.md @@ -1,6 +1,6 @@ --- layout: full.html.hbs -title: Pipes +title: Documentation order: 300 --- @@ -10,12 +10,11 @@ Pipes are functions plugged to [events]({{ site_base_path }}plugins/1/events/), Pipes can: -* Decide to abort a task. If a pipe throws an error, Kuzzle interrupts the task, and forwards a standardized version of the thrown error to the originating user -* Change the received information. Kuzzle will use the updated information upon resuming the task +- Decide to abort a task. If a pipe throws an error, Kuzzle interrupts the task, and forwards a standardized version of the thrown error to the originating user +- Change the received information. Kuzzle will use the updated information upon resuming the task
If a pipe takes too long to respond, Kuzzle will eventually abort the entire task with a GatewayTimeout error. The timeout value can be changed in the configuration files.
- --- ## Usage @@ -33,8 +32,8 @@ If multiple pipes are plugged to the same event (either from the same plugin or Pipes must notify Kuzzle about their completion by one of these two means: -* by calling the `callback(error, request)` function received as their last argument (leave the `error` null if the pipe executed successfully) -* by returning a promise, resolved (or rejected) with a valid [Request]({{ site_base_path }}guide/1/essentials/request-and-response-format) upon the completion of the pipe +- by calling the `callback(error, request)` function received as their last argument (leave the `error` null if the pipe executed successfully) +- by returning a promise, resolved (or rejected) with a valid [Request]({{ site_base_path }}guide/1/essentials/request-and-response-format) upon the completion of the pipe
You must either call the callback with a valid Request or return a promise resolving to one.
@@ -46,25 +45,27 @@ If a pipe throws an error, it is advised to throw one of the available [KuzzleEr ```javascript module.exports = class PipePlugin { - constructor () {} + constructor() {} /* Required plugin initialization function (see the "Plugin prerequisites" section) */ - init (customConfig, context) { + init(customConfig, context) { /* Attaches the plugin function "restrictUser" to the Kuzzle event "document:afterGet" */ this.pipes = { - 'document:afterGet': (...args) => this.restrictUser(...args) + 'document:afterGet': this.restrictUser.bind(this) }; } // Restrict document access to creator with callback - restrictUser (request, callback) { - if (request.context.user._id !== request.result._source._kuzzle_info.author) { + restrictUser(request, callback) { + if ( + request.context.user._id !== request.result._source._kuzzle_info.author + ) { callback(new this.context.errors.NotFoundError(), null); return; } @@ -73,8 +74,10 @@ module.exports = class PipePlugin { } // Restrict document access to creator with async method - async restrictUser (request) { - if (request.context.user._id !== request.result._source._kuzzle_info.author) { + async restrictUser(request) { + if ( + request.context.user._id !== request.result._source._kuzzle_info.author + ) { throw new this.context.errors.NotFoundError(); } @@ -83,13 +86,15 @@ module.exports = class PipePlugin { } // Restrict document access to creator with traditional promises - restrictUser (request) { - if (request.context.user._id !== request.result._source._kuzzle_info.author) { + restrictUser(request) { + if ( + request.context.user._id !== request.result._source._kuzzle_info.author + ) { return Promise.reject(new this.context.errors.NotFoundError()); } // You must return a promise resolving to the original request if there is no error return Promise.resolve(request); } -} +}; ``` diff --git a/src/plugins/1/pipes/index.md b/src/plugins/1/pipes/index.md new file mode 100644 index 000000000..75e0ffdfb --- /dev/null +++ b/src/plugins/1/pipes/index.md @@ -0,0 +1,5 @@ +--- +layout: full.html.hbs +title: Pipes +order: 3 +--- diff --git a/src/plugins/1/strategies/auth-functions/index.md b/src/plugins/1/strategies/auth-functions/index.md new file mode 100644 index 000000000..44d4aae40 --- /dev/null +++ b/src/plugins/1/strategies/auth-functions/index.md @@ -0,0 +1,383 @@ +--- +layout: full.html.hbs +title: Authentication methods +order: 1 +--- + +### Methods + +The `methods` part of the `strategies` object can contain the following properties: + +| Arguments | Type | Description | +| --------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| `create` |
string
| The name of the exposed [create]({{ site_base_path }}plugins/1/essentials/strategies/#create-default) function | +| `delete` |
string
| The name of the exposed [delete]({{ site_base_path }}plugins/1/essentials/strategies/#delete-default) function | +| `exists` |
string
| The name of the exposed [exists]({{ site_base_path }}plugins/1/essentials/strategies/#exists-default) function | +| `update` |
string
| The name of the exposed [update]({{ site_base_path }}plugins/1/essentials/strategies/#update-default) function | +| `validate` |
string
| The name of the exposed [validate]({{ site_base_path }}plugins/1/essentials/strategies/#update-default) function | +| `verify` |
string
| The name of the exposed [verify]({{ site_base_path }}plugins/1/essentials/strategies/#verify-default) function | +| `afterRegister` |
string
| (optional) The name of the exposed [afterRegister]({{ site_base_path }}plugins/1/essentials/strategies/#optional-afterregister-default) function | +| `getById` |
string
| (optional) The name of the exposed [getById]({{ site_base_path }}plugins/1/essentials/strategies/#optional-getbyid-default) function | +| `getInfo` |
string
| (optional) The name of the exposed [getInfo]({{ site_base_path }}plugins/1/essentials/strategies/#optional-getinfo-default) function | + +Even though each strategy must declare its own set of properties, the same strategy method can be used by multiple strategies. + +--- + +## create + +The `create` function adds credentials to a user. + +For security reasons, plugins are entirely responsible of how credentials are managed, storage included: Kuzzle does not read, modify, or store credentials. + +If needed, Kuzzle exposes a secure and isolated storage space for each plugin. It can be accessed using the [Repository]({{ site_base_path }}plugins/1/constructors/repository) constructor. + +### Arguments + +```js +create(request, credentials, kuid, strategy); +``` + +
+ +| Arguments | Type | Description | +| ------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| `request` |
Request
| API request asking for the credentials creation | +| `credentials` |
object
| New credentials to create, already validated by this strategy's [validate](#validate) function | +| `kuid` |
string
| User's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid) | +| `strategy` |
string
| Authentication strategy used by these credentials | + +### Returned value + +The `create` function must return a promise, resolving to an object. The content of that object depends on this authentication strategy; usually a feedback about the created credentials is expected. That object can be left empty. + +
The object resolved by the promise is directly forwarded to the originating user. For security reasons, it must only contain non sensitive information.
+ +--- + +## delete + +The `delete` function deletes a user's credentials. + +### Arguments + +```js +delete (request, kuid, strategy); +``` + +
+ +| Arguments | Type | Description | +| ---------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| `request` |
Request
| API request asking for the credentials deletion | +| `kuid` |
string
| User's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid) | +| `strategy` |
string
| Authentication strategy name | + +### Returned value + +The `delete` function must return a promise. The resolved value is not used. + +--- + +## exists + +The `exists` function checks whether a user is known to the authentication strategy. + +### Arguments + +```js +exists(request, kuid, strategy); +``` + +
+ +| Arguments | Type | Description | +| ---------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| `request` |
Request
| Source API request | +| `kuid` |
string
| User's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid) | +| `strategy` |
string
| Authentication strategy name | + +### Returned value + +The `exists` function must return a promise, resolving to a boolean representing the result of the user existence check. + +--- + +## update + +The `update` function updates a user's credentials. + +### Arguments + +```js +update(request, credentials, kuid, strategy); +``` + +
+ +| Arguments | Type | Description | +| ------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| `request` |
Request
| Source API request | +| `credentials` |
object
| Updated credentials.
Those are already validated by this strategy's [validate](#validate) function | +| `kuid` |
string
| User's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid) | +| `strategy` |
string
| Authentication strategy name | + +### Returned value + +The `update` function must return a promise, resolving to an object. The content of that object depends on this authentication strategy; usually a feedback about the updated credentials is expected. That object can be left empty. + +
The object resolved by the promise is directly forwarded to the originating user. For security reasons, it must only contain non sensitive information.
+ +--- + +## validate + +The `validate` function verifies that credentials are well-formed. + +### Arguments + +```js +validate(request, credentials, kuid, strategy, isUpdate); +``` + +
+ +| Arguments | Type | Description | +| ------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `request` |
Request
| Source API request | +| `credentials` |
object
| Credentials to validate | +| `kuid` |
string
| User's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid) | +| `strategy` |
string
| Authentication strategy name | +| `isUpdate` |
boolean
| Tells whether the request is a credentials update. In the case of an update, the `credentials` object may only contain changes to be applied, instead of a complete credentials description | + +### Returned value + +The function `validate` must return a promise. The resolved value, if there is one, is ignored. + +--- + +## verify + +The [verify](http://passportjs.org/docs/configure) function authenticates a user. + +The number of arguments taken by the `verify` function depends on the authentication strategy. +For instance, a `local` authentication strategy requires that the `verify` function validates both a user name and a password, so these two arguments will have to be provided to the `verify` function. + +### Arguments + +```js +verify(payload, ...) +``` + +
+ +| Arguments | Type | Description | +| --------- | ----------------- | ------------------------------------------------------------ | +| `payload` |
object
| Login request made to passport | +| `...` |
\*
| Additional arguments; depends on the authentication strategy | + +#### payload + +The `payload` object has the following properties: + +
+ +| Properties | Type | Description | +| ---------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | +| `original` |
Request
| Source API login request | +| `query` |
object
| Direct link to `original.input.args`, containing the optional request arguments | +| `body` |
object
| Direct link to `original.input.body`, containing the request body content | + +### Returned value + +The `verify` function must return a promise, resolving to an object with the following properties: + +
+ +| Properties | Type | Description | +| ---------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `kuid` |
string
| If the authentication succeeds, this property must be set to the user's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid). Otherwise, this must be set to `null` | +| `message` |
string
| If `kuid` is set to `null` (authentication failed), this optional property can be set with a rejection reason | + +
A failed authentication is not an error. The returned promise should only be rejected if an actual error occurs.
+ +--- + +## (optional) afterRegister + +The `afterRegister` function is called when the Passport.js strategy is instantiated by Kuzzle. + +### Arguments + +```js +afterRegister(strategyInstance); +``` + +
+ +| Arguments | Type | Description | +| ------------------ | ----------------- | --------------------------------- | +| `strategyInstance` |
object
| The Passport.js strategy instance | + +--- + +## (optional) getById + +The `getById` function returns credentials information using the authentication strategy's user identifier (which may not be the [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid)). + +If this function is not implemented, an empty object is returned by Kuzzle instead. + +
The returned information can be forwarded to users. For security reasons, it must only contain non sensitive information.
+ +### Arguments + +```js +getById(request, id, strategy); +``` + +
+ +| Arguments | Type | Description | +| ---------- | --------------------------------------------------------------------------------- | -------------------------------------------------- | +| `request` |
Request
| The API request asking for credentials information | +| `id` |
string
| Strategy's user identifier | +| `strategy` |
string
| Authentication strategy name | + +### Returned value + +The `getById` function must return a promise, resolving to an object containing credentials information. It can be left empty. + +--- + +## (optional) getInfo + +The `getInfo` function returns information about a user's credentials. + +If this function is not implemented, an empty object is returned by Kuzzle instead. + +
The returned information can be forwarded to users. For security reasons, it must only contain non sensitive information.
+ +### Arguments + +```js +getInfo(request, kuid, strategy); +``` + +
+ +| Arguments | Type | Description | +| ---------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| `request` |
Request
| The API request asking for credentials information | +| `kuid` |
string
| User's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid) | +| `strategy` |
string
| Authentication strategy name | + +### Returned value + +The `getInfo` function must return a promise, resolving to an object containing credentials information. It can be left empty. + +--- + +## Example + +```javascript +module.exports = class AuthenticationPlugin { + constructor() {} + + /** + Required plugin initialization function + (see the "Plugin prerequisites" section) + */ + init (customConfig, context) { + this.authenticators = { + StrategyConstructor: require('some-passport-strategy') + }; + + this.strategies = { + '': { + config: { + // Must be declared in this.authenticators + authenticator: 'StrategyConstructor', + + // The list of fields that have to be provided in the credentials + fields: ['login', 'password'] + }, + methods: { + create: 'create', + delete: 'delete', + exists: 'exists', + update: 'update', + validate: 'validate', + verify: 'verify' + } + } + }; + } + + /** + * Stores the provided credentials + * Must keep a link between the persisted credentials + * and the kuid + */ + create (request, credentials, kuid) { + // store credentials + return Promise.resolve({/* non sensitive credentials info */}); + } + + /** + * Removes the user's stored credentials from + * the plugin persistence layer + */ + delete (request, kuid) { + // remove credentials + return Promise.resolve(); + } + + /** + * Checks if user's credentials exist in the persistence layer + */ + exists (request, kuid) { + // check credentials existence + return Promise.resolve(/* boolean value */); + } + + /** + * Updates the user's credentials information in the + * persistence layer + * + * @param {KuzzleRequest} request + * @param {object} credentials + * @param {string} kuid + * @returns {Promise} + */ + update (request, credentials, kuid) { + // update credentials + return Promise.resolve(/* non sensitive credentials info */); + } + + /** + * Validates credentials against the strategy rules + * (required fields, password strength, username uniqueness, ...) + */ + validate (request, credentials, kuid, strategy, isUpdate) { + // validate credentials + return Promise.resolve(/* true|false */); + } + + /** + * Returns an object with the authenticated user id if successful, + * and a reason if the authentication fails + */ + verify (request, ...credentials) { + const kuid = /* authentification */; + + if (kuid) { + return Promise.resolve({kuid}); + } + + return Promise.resolve({ + kuid: null, + message: 'Login failed - You shall not pass! Reason: ...' + }); + } +} +``` diff --git a/src/plugins/1/strategies/index.md b/src/plugins/1/strategies/index.md new file mode 100644 index 000000000..7d3fa252d --- /dev/null +++ b/src/plugins/1/strategies/index.md @@ -0,0 +1,5 @@ +--- +layout: full.html.hbs +title: Strategies +order: 5 +--- diff --git a/src/plugins/1/strategies/overview/index.md b/src/plugins/1/strategies/overview/index.md new file mode 100644 index 000000000..40f6fcf81 --- /dev/null +++ b/src/plugins/1/strategies/overview/index.md @@ -0,0 +1,68 @@ +--- +layout: full.html.hbs +title: Overview +order: 0 +--- + +# Strategies + +Plugins can add new authentication strategies to Kuzzle. +For example, our official [OAUTH2 Authentication plugin](https://github.com/kuzzleio/kuzzle-plugin-auth-passport-oauth) adds OAUTH2 support to Kuzzle. + +All authentication strategies supported by [Passport.js](http://passportjs.org/) can be integrated to Kuzzle. + +--- + +## Registering authentication strategies + +[Passport.js](http://passportjs.org) provides a wide range of authentication strategies. +Custom authentication strategies can also be implemented by subclassing the abstract [Passport Strategy](https://github.com/jaredhanson/passport-strategy) class. + +To register strategies to Kuzzle, a `authenticators` object property must be exposed by the plugin, for instance: + +```js +this.authenticators = { + Local: require('passport-local'), + Oauth2: require('passport-oauth2') +}; +``` + +--- + +## Credentials security + +User credentials are very sensitive data, and these must be properly isolated to prevent security vulnerabilities. +To do so, Kuzzle guarantees that it never interprets, modifies, or stores credentials information. + +Instead, Kuzzle: + +- provides a global user unique identifier (referred from now on as the user's [kuid]({{ site_base_path }}guide/1/kuzzle-depth/authentication/#the-kuzzle-user-identifier-kuid)), giving the possibility to a user to authenticate with multiple strategies +- entrusts implemented strategies with credentials protection, validation, verification and storage + +--- + +## Managing credentials + +There are two ways of interfacing credentials management: + +- statically, by exposing a `strategies` object +- dynamically, by using the dedicated [strategy accessors]({{ site_base_path }}plugins/1/accessors/strategies) + +Whether strategies are added statically or dynamically, the `strategies` object must expose the following properties: + +| Arguments | Type | Description | +| --------- | ----------------- | ------------------------------------- | +| `config` |
object
| Authentication strategy configuration | +| `methods` |
object
| List of exposed methods | + +### config + +The `config` part of the `strategies` object can contain the following properties: + +| Arguments | Type | Description | +| --------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `authenticator` |
string
| One of the exposed [authenticators]({{ site_base_path }}plugins/1/essentials/strategies/#registering-authentication-strategies-default) name | +| `constructor` |
object
| {{{deprecated "1.4.0"}}} (use the `authenticator` property instead)
The constructor of the Passport.js strategy. Does not support [dynamic strategy registration]({{ site_base_path }}plugins/1/accessors/strategies) | +| `authenticateOptions` |
object
| (optional) Additional options to be provided to the Passport's [authenticate method](http://passportjs.org/docs/authenticate) | +| `fields` |
string[]
| (optional) The list of accepted field names by the strategy credentials.
The list is informative only, meant to be used by the [getAllCredentialFields]({{ site_base_path }}api/1/controller-security/get-all-credential-fields/) and the [getCredentialFields]({{ site_base_path }}api/1/controller-security/get-credential-fields) API methods | +| `strategyOptions` |
object
| (optional) Options provided to the Passport.js strategy constructor | diff --git a/src/protocols/1/essentials/getting-started/index.md b/src/protocols/1/essentials/getting-started/index.md index e2346340b..1cd4fea58 100644 --- a/src/protocols/1/essentials/getting-started/index.md +++ b/src/protocols/1/essentials/getting-started/index.md @@ -6,7 +6,7 @@ order: 0 # Getting Started -Kuzzle has native support for the following network protocols: HTTP, Websocket and Socket.io. +Kuzzle has native support for the following network protocols: [HTTP]({{ site_base_path }}protocols/1/native-protocols/http), [MQTT]({{ site_base_path }}protocols/1/native-protocols/mqtt) (disabled by default), [Websocket]({{ site_base_path }}protocols/1/native-protocols/websocket) and [Socket.io]({{ site_base_path }}protocols/1/native-protocols/socketio). However, any number of protocols can be implemented, adding new network capabilities. @@ -18,8 +18,6 @@ Protocols are provided with objects to interact with Kuzzle: * [EntryPoint]({{ site_base_path }}protocols/1/entrypoint): base communication layer (declare user connections, forward API requests, ...) * [context]({{ site_base_path }}protocols/1/context): utilities and object constructors not directly related to network communications -Protocol implementation example: [MQTT](https://github.com/kuzzleio/protocol-mqtt) - --- ## Prerequisites diff --git a/src/protocols/1/essentials/broadcast/index.md b/src/protocols/1/methods/broadcast/index.md similarity index 100% rename from src/protocols/1/essentials/broadcast/index.md rename to src/protocols/1/methods/broadcast/index.md diff --git a/src/protocols/1/essentials/disconnect/index.md b/src/protocols/1/methods/disconnect/index.md similarity index 100% rename from src/protocols/1/essentials/disconnect/index.md rename to src/protocols/1/methods/disconnect/index.md diff --git a/src/protocols/1/methods/index.md b/src/protocols/1/methods/index.md new file mode 100644 index 000000000..36deb02c4 --- /dev/null +++ b/src/protocols/1/methods/index.md @@ -0,0 +1,6 @@ +--- +layout: full.html.hbs +title: Protocol Methods +description: Extend Kuzzle communication capabilities +order: 0 +--- diff --git a/src/protocols/1/essentials/init/index.md b/src/protocols/1/methods/init/index.md similarity index 100% rename from src/protocols/1/essentials/init/index.md rename to src/protocols/1/methods/init/index.md diff --git a/src/protocols/1/essentials/joinchannel/index.md b/src/protocols/1/methods/joinchannel/index.md similarity index 100% rename from src/protocols/1/essentials/joinchannel/index.md rename to src/protocols/1/methods/joinchannel/index.md diff --git a/src/protocols/1/essentials/leavechannel/index.md b/src/protocols/1/methods/leavechannel/index.md similarity index 100% rename from src/protocols/1/essentials/leavechannel/index.md rename to src/protocols/1/methods/leavechannel/index.md diff --git a/src/protocols/1/essentials/notify/index.md b/src/protocols/1/methods/notify/index.md similarity index 100% rename from src/protocols/1/essentials/notify/index.md rename to src/protocols/1/methods/notify/index.md diff --git a/src/protocols/1/native-protocols/http/index.md b/src/protocols/1/native-protocols/http/index.md new file mode 100644 index 000000000..4fa692fa6 --- /dev/null +++ b/src/protocols/1/native-protocols/http/index.md @@ -0,0 +1,32 @@ +--- +layout: full.html.hbs +title: HTTP +order: 0 +--- + +# HTTP + +## Configuration + +The protocol can be configured via the [kuzzlerc configuration file]({{ site_base_path }}guide/1/essentials/configuration/), under the ``server > protocols > http`` section. + +| Option | Type | Description | Default | +|---|---|---|---| +| ``enabled`` |
boolean
| Enable/Disable HTTP protocol support | ``true`` | +| ``maxFormFileSize`` |
string
| Maximum size of requests sent via http forms | ``1mb`` | +| ``maxEncodingLayers`` |
integer
| Maximum number of encoding layers that can be applied to an http message, using the Content-Encoding header. This parameter is meant to prevent abuses by setting an abnormally large number of encodings, forcing Kuzzle to allocate as many decoders to handle the incoming request | ``3`` | +| ``allowCompression`` |
boolean
| Enable support for compressed requests, using the Content-encoding header. Currently supported compression algorithms: gzip, deflate, identity. Note: "identity" is always an accepted value, even if compression support is disabled | ``true`` | + +### Configure listening port + +
+HTTP, WebSocket and Socket.IO protocols share the same underlying server instance. Modifying the listening port will impact all these three protocols. +
+ +By default, Kuzzle listens to the ``7512`` port. + +The port can be modified under the ``server > port`` section of [Kuzzle configuration]({{ site_base_path }}guide/1/essentials/configuration/). + +## Limitations + +Due to the synchronous nature of the HTTP protocol, real-time messaging is not supported. diff --git a/src/protocols/1/native-protocols/index.md b/src/protocols/1/native-protocols/index.md new file mode 100644 index 000000000..2215eb86e --- /dev/null +++ b/src/protocols/1/native-protocols/index.md @@ -0,0 +1,6 @@ +--- +layout: full.html.hbs +title: Native Protocols +description: Extend Kuzzle communication capabilities +order: 0 +--- diff --git a/src/protocols/1/native-protocols/mqtt/index.md b/src/protocols/1/native-protocols/mqtt/index.md new file mode 100644 index 000000000..bf53d780e --- /dev/null +++ b/src/protocols/1/native-protocols/mqtt/index.md @@ -0,0 +1,185 @@ +--- +layout: full.html.hbs +title: MQTT +order: 0 +--- +# MQTT + +
+By default, the MQTT protocol is disabled in Kuzzle configuration. +
protocols > mqtt`` section. + +| Option | Type | Description | Default | +|---|---|---|---| +| ``enabled`` |
boolean
| Enable/Disable the MQTT protocol support | ``false`` | +| ``allowPubSub`` |
boolean
| Allow MQTT pub/sub capabilities or restrict to Kuzzle requests only | ``false`` | +| ``developmentMode`` |
boolean
| Switches ``responseTopic`` back to a regular public topic | ``false`` | +| ``disconnectDelay`` |
integer
| Delay in ms to apply between a disconnection notification is received and the connection is actually removed | 250 | +| ``requestTopic`` |
string
| Name of the topic listened by the plugin for requests | ``"Kuzzle/request"`` | +| ``responseTopic`` |
string
| Name of the topic clients should listen to get requests result | ``"Kuzzle/response"`` | +| ``server`` |
object
| Constructor options pased to underlying mqtt server. See [mosca documentation](https://github.com/mcollina/mosca/wiki/Mosca-advanced-usage#other-options-of-mosca-the-ones-we-inserted-in-our-moscasettings-var) for further reference. | ``{port: 1883}`` | + +example: + +``.kuzzlerc`` +```json +{ + "server": { + "protocols": { + "mqtt": { + "allowPubSub": true + } + } + } +} +``` + +## How to use + +### Sending an API request and getting the response + +By default, the MQTT protocol listens to the ``Kuzzle/request`` MQTT topic (see [configuration](#configuration)) for requests to the [Kuzzle API]({{ site_base_path }}api/1/essentials/connecting-to-kuzzle/). + +It then forwards Kuzzle response to the ``Kuzzle/response`` MQTT topic, **and only to the client who made the initial request**. + +The order of responses is not guaranteed to be the same than the order of requests. To link a response to its original request, use the ``requestId`` attribute: the response will have the same ``requestId`` than the one provided in the request. + +Example using [MQTT Node module](https://www.npmjs.com/package/mqtt): _to use a CLI client, you will need to enable development mode. Please refer to [the dedicated section below](#development-mode) for instruction and examples_ + +```javascript +const + mqtt = require('mqtt'), + client = mqtt.connect({host: 'localhost'}); + +// Sending a volatile message +client.publish('Kuzzle/request', JSON.stringify({ + index: 'index', + collection: 'collection', + controller: 'realtime', + action: 'publish', + requestId: 'some unique ID', + body: { some: "message" } +})); + +// Getting Kuzzle's response +client.on('message', (topic, raw) => { + const message = JSON.parse(Buffer.from(raw)); + + // API results topic + if (topic === 'Kuzzle/response') { + // Response to our "publish" request + if (message.requestId === 'some unique ID') { + console.log('Message publication result: ', message); + } + } +}); +``` + +### Using Kuzzle subscriptions + +Kuzzle allows to [subscribe](https://docs.kuzzle.io/api/1/controller-realtime/subscribe/) to messages and events using advanced filters. + +Each time a subscription is sent, a dedicated MQTT topic is created, named after the ``channel`` property issued by Kuzzle. + +Here are the steps to perform a Kuzzle subscription using MQTT: + +- Send a subscription request to Kuzzle +- Listen to the request's response to ge the ``channel`` identifier +- Subscribe to the MQTT topic named after this channel identifier + +Example using [MQTT Node module](https://www.npmjs.com/package/mqtt): + +```javascript +const + mqtt = require('mqtt'), + client = mqtt.connect({host: 'localhost'}), + channels = []; + +// Sending a volatile message +client.publish('Kuzzle/request', JSON.stringify({ + index: 'index', + collection: 'collection', + controller: 'realtime', + action: 'subscribe', + requestId: 'some unique ID', + body: { + term: { + some: 'filter' + } + } +})); + +// Getting Kuzzle's response +client.on('message', (topic, raw) => { + const message = JSON.parse(Buffer.from(raw)); + + // API results topic + if (topic === 'Kuzzle/response') { + // Response to our "publish" request + if (message.requestId === 'some unique ID') { + channels.push(message.result.channel); + client.subscribe(message.result.channel); + } + } + else if (channels.indexOf(topic) !== -1) { + // Subscription notification + console.log('Notification: ', message); + } +}); +``` + +## Authorizations + +### Publishing + +If ``allowPubSub`` is set to ``false``, clients can only publish to the ``requestTopic`` topic (defaults to ``Kuzzle/request``). + +If ``allowPubSub`` is set to ``true``, clients are only forbidden to publish to the ``responseTopic`` topic (defaults to ``Kuzzle/response``). + +
+ Wildcards subcriptions are not allowed +
+ Do not use development mode in production! + protocols > socketio`` section. + +| Option | Type | Description | Default | +|---|---|---|---| +| ``enabled`` |
boolean
| Enable/Disable Socket.IO protocol support | ``true`` | +| ``origins`` |
string
| Value of Access-Control-Allow-Origin header to answer the upgrade request | ``*:*`` | + +### Configure listening port + +
+HTTP, WebSocket and Socket.IO protocols share the same underlying server instance. Modifying the listening port will impact all these three protocols. +
+ +By default, Kuzzle listens to the ``7512`` port. + +The port can be modified under the ``server > port`` section of [Kuzzle configuration]({{ site_base_path }}guide/1/essentials/configuration/). diff --git a/src/protocols/1/native-protocols/websocket/index.md b/src/protocols/1/native-protocols/websocket/index.md new file mode 100644 index 000000000..d5e0fa206 --- /dev/null +++ b/src/protocols/1/native-protocols/websocket/index.md @@ -0,0 +1,25 @@ +--- +layout: full.html.hbs +title: WebSocket +order: 0 +--- +# WebSocket + +## Configuration + +The protocol can be configured via the [kuzzlerc configuration file]({{ site_base_path }}guide/1/essentials/configuration/), under the ``server > protocols > websocket`` section. + +| Option | Type | Description | Default | +|---|---|---|---| +| ``enabled`` |
boolean
| Enable/Disable WebSocket protocol support | ``true`` | +| ``heartbeat`` |
integer
| The time, in milliseconds, between the server's PING requests. Setting this value to ``0`` disables PING/PONG requests entirely. | ``60000`` | + +### Configure listening port + +
+HTTP, WebSocket and Socket.IO protocols share the same underlying server instance. Modifying the listening port will impact all these three protocols. +
+ +By default, Kuzzle listens to the ``7512`` port. + +The port can be modified under the ``server > port`` section of [Kuzzle configuration]({{ site_base_path }}guide/1/essentials/configuration/). diff --git a/src/sdk-reference/cpp/1/collection/create/index.md b/src/sdk-reference/cpp/1/collection/create/index.md index 997dc6a27..4ea4b9460 100644 --- a/src/sdk-reference/cpp/1/collection/create/index.md +++ b/src/sdk-reference/cpp/1/collection/create/index.md @@ -6,11 +6,19 @@ description: Create a new collection # create -Creates a new [collection]({{ site_base_path }}guide/1/essentials/persisted) in Kuzzle via the persistence engine, in the provided `index`. -You can also provide an optional data mapping that allow you to exploit the full capabilities of our -persistent data storage layer, [ElasticSearch](https://www.elastic.co/products/elasticsearch) (check here the [mapping capabilities of ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/reference/5.4/mapping.html)). +Creates a new [collection]({{ site_base_path }}guide/1/essentials/persisted) in Kuzzle via the persistence engine, in the provided index. -This method will only update the mapping if the collection already exists. +{{{since "Kuzzle 1.3.0"}}} + +You can also provide an optional body with a [collection mapping]({{ site_base_path }}guide/1/essentials/database-mappings) that allow you to exploit the full capabilities of our persistent data storage layer. + +This method will only update the mapping when the collection already exists. + +{{{since "Kuzzle 1.7.1"}}} + +You can define the collection [dynamic mapping policy]({{ site_base_path}}guide/1/essentials/database-mappings/#dynamic-mapping-policy) by setting the `dynamic` field to the desired value. + +You can define [collection additional metadata]({{ site_base_path}}guide/1/essentials/database-mappings/#collection-metadata) within the `_meta` root field. ## Signature @@ -40,16 +48,19 @@ void create( |--------------|---------|-------------| | `index` |
const std::string&
| Index name | | `collection` |
const std::string&
| Collection name | -| `mapping` |
const std::string*
| JSON string representing the collection data mapping | +| `mapping` |
const std::string*
| JSON string representing the collection mapping | | `options` |
kuzzleio::query_options\*
| Query options | ### mapping -A JSON string representing the collection data mapping. +A JSON string representing the collection mapping. -The mapping must have a root field `properties` that contain the mapping definition: ```json { + "dynamic": "[true|false|strict]", + "_meta": { + "field": "value" + }, "properties": { "field1": { "type": "text" }, "field2": { @@ -61,7 +72,7 @@ The mapping must have a root field `properties` that contain the mapping definit } ``` -You can see the full list of Elasticsearch mapping types [here](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping.html). +More informations about database mappings [here]({{ site_base_path}}guide/1/essentials/database-mappings). ### options diff --git a/src/sdk-reference/cpp/1/collection/create/snippets/create.cpp b/src/sdk-reference/cpp/1/collection/create/snippets/create.cpp index d8e53b087..bd2a1747b 100644 --- a/src/sdk-reference/cpp/1/collection/create/snippets/create.cpp +++ b/src/sdk-reference/cpp/1/collection/create/snippets/create.cpp @@ -1,5 +1,9 @@ try { std::string mapping = R"({ + "dynamic": "false", + "_meta": { + "area": "Panipokhari" + }, "properties": { "license": { "type": "keyword" }, "driver": { diff --git a/src/sdk-reference/cpp/1/collection/get-mapping/index.md b/src/sdk-reference/cpp/1/collection/get-mapping/index.md index 466b27589..be4bb69e6 100644 --- a/src/sdk-reference/cpp/1/collection/get-mapping/index.md +++ b/src/sdk-reference/cpp/1/collection/get-mapping/index.md @@ -37,7 +37,7 @@ Additional query options ## Return -A JSON string representing the collection data mapping. +A JSON string representing the collection mapping. ## Usage diff --git a/src/sdk-reference/cpp/1/collection/get-mapping/snippets/get-mapping.cpp b/src/sdk-reference/cpp/1/collection/get-mapping/snippets/get-mapping.cpp index 174a6de29..676d19505 100644 --- a/src/sdk-reference/cpp/1/collection/get-mapping/snippets/get-mapping.cpp +++ b/src/sdk-reference/cpp/1/collection/get-mapping/snippets/get-mapping.cpp @@ -2,7 +2,7 @@ try { std::string mapping = kuzzle->collection->getMapping("nyc-open-data", "yellow-taxi"); std::cout << mapping << std::endl; - // {"properties":{"license":{"type":"keyword"},"driver":{"properties":{"name":{"type":"keyword"},"curriculum":{"type":"text"}}}}} + // {"dynamic": "false","_meta": { "area": "Panipokhari" }, "properties":{"license":{"type":"keyword"},"driver":{"properties":{"name":{"type":"keyword"},"curriculum":{"type":"text"}}}}} } catch (kuzzleio::KuzzleException &e) { std::cerr << e.what() << std::endl; } diff --git a/src/sdk-reference/cpp/1/collection/update-mapping/index.md b/src/sdk-reference/cpp/1/collection/update-mapping/index.md index fbe3237c0..9be9d9149 100644 --- a/src/sdk-reference/cpp/1/collection/update-mapping/index.md +++ b/src/sdk-reference/cpp/1/collection/update-mapping/index.md @@ -6,9 +6,13 @@ description: Update the collection mapping # updateMapping -Update the collection mapping. -Mapping allow you to exploit the full capabilities of our -persistent data storage layer, [ElasticSearch](https://www.elastic.co/products/elasticsearch) (check here the [mapping capabilities of ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping.html)). +Updates a collection mapping. + +{{{since "Kuzzle 1.7.1"}}} + +You can define the collection [dynamic mapping policy]({{ site_base_path}}guide/1/essentials/database-mappings/#dynamic-mapping-policy) by setting the `dynamic` field to the desired value. + +You can define [collection additional metadata]({{ site_base_path}}guide/1/essentials/database-mappings/#collection-metadata) within the `_meta` root field. ## Signature @@ -31,16 +35,19 @@ void updateMapping( |--------------|---------|-------------| | `index` |
const std::string&
| Index name | | `collection` |
const std::string&
| Collection name | -| `mapping` |
const std::string*
| JSON string representing the collection data mapping | +| `mapping` |
const std::string*
| JSON string representing the collection mapping | | `options` |
kuzzleio::query_options\*
| Query options | ### mapping -A JSON string representing the collection data mapping. +A JSON string representing the collection mapping. -The mapping must have a root field `properties` that contain the mapping definition: ```json { + "dynamic": "[true|false|strict]", + "_meta": { + "field": "value" + }, "properties": { "field1": { "type": "text" }, "field2": { @@ -52,7 +59,8 @@ The mapping must have a root field `properties` that contain the mapping definit } ``` -You can see the full list of Elasticsearch mapping types [here](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping.html). +More informations about database mappings [here]({{ site_base_path}}guide/1/essentials/database-mappings). + ### options diff --git a/src/sdk-reference/cpp/1/collection/update-mapping/snippets/update-mapping.cpp b/src/sdk-reference/cpp/1/collection/update-mapping/snippets/update-mapping.cpp index 6ed441c28..705382a43 100644 --- a/src/sdk-reference/cpp/1/collection/update-mapping/snippets/update-mapping.cpp +++ b/src/sdk-reference/cpp/1/collection/update-mapping/snippets/update-mapping.cpp @@ -1,5 +1,9 @@ try { std::string mapping = R"({ + "dynamic": "false", + "_meta": { + "area": "Panipokhari" + }, "properties": { "plate": { "type": "keyword" } } diff --git a/src/sdk-reference/go/1/collection/create/index.md b/src/sdk-reference/go/1/collection/create/index.md index c3d77ea59..c12cb9ecd 100644 --- a/src/sdk-reference/go/1/collection/create/index.md +++ b/src/sdk-reference/go/1/collection/create/index.md @@ -6,9 +6,19 @@ description: Create a new collection # create -Creates a new [collection]({{ site_base_path }}guide/1/essentials/persisted) in Kuzzle via the persistence engine, in the provided `index`. -You can also provide an optional data mapping that allow you to exploit the full capabilities of our -persistent data storage layer, [ElasticSearch](https://www.elastic.co/products/elasticsearch) (check here the [mapping capabilities of ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/reference/5.4/mapping.html)). +Creates a new [collection]({{ site_base_path }}guide/1/essentials/persisted) in Kuzzle via the persistence engine, in the provided index. + +{{{since "Kuzzle 1.3.0"}}} + +You can also provide an optional body with a [collection mapping]({{ site_base_path }}guide/1/essentials/database-mappings) that allow you to exploit the full capabilities of our persistent data storage layer. + +This method will only update the mapping when the collection already exists. + +{{{since "Kuzzle 1.7.1"}}} + +You can define the collection [dynamic mapping policy]({{ site_base_path}}guide/1/essentials/database-mappings/#dynamic-mapping-policy) by setting the `dynamic` field to the desired value. + +You can define [collection additional metadata]({{ site_base_path}}guide/1/essentials/database-mappings/#collection-metadata) within the `_meta` root field. This method will only update the mapping if the collection already exists. @@ -24,16 +34,19 @@ Create(index string, collection string, mapping json.RawMessage, options types.Q |--------------|---------|-------------|---------- | ``index`` | string | Index name | yes | | ``collection`` | string | Collection name | yes | -| ``mapping`` | json.RawMessage | Collection data mapping in JSON format | no | +| ``mapping`` | json.RawMessage | Collection mapping in JSON format | no | | `options` | QueryOptions | Query options | no | -### **mapping** +### mapping -An string containing the JSON representation of the collection data mapping. +A `json.RawMessage` containing the representation of the collection mapping. -The mapping must have a root field `properties` that contain the mapping definition: ```json { + "dynamic": "[true|false|strict]", + "_meta": { + "field": "value" + }, "properties": { "field1": { "type": "text" }, "field2": { @@ -45,9 +58,9 @@ The mapping must have a root field `properties` that contain the mapping definit } ``` -You can see the full list of Elasticsearch mapping types [here](https://www.elastic.co/guide/en/elasticsearch/reference/5.4/mapping.html). +More informations about database mappings [here]({{ site_base_path}}guide/1/essentials/database-mappings) -### **options** +### options Additional query options diff --git a/src/sdk-reference/go/1/collection/create/snippets/create.go b/src/sdk-reference/go/1/collection/create/snippets/create.go index 712ee8115..73134752f 100644 --- a/src/sdk-reference/go/1/collection/create/snippets/create.go +++ b/src/sdk-reference/go/1/collection/create/snippets/create.go @@ -1,4 +1,4 @@ -mapping := json.RawMessage(`{"properties":{"license": {"type": "keyword"}}}`) +mapping := json.RawMessage(`{ "dynamic": "false","_meta": { "area": "Panipokhari" }, "properties":{"license": {"type": "keyword"}}}`) err := kuzzle.Collection.Create("nyc-open-data", "yellow-taxi", mapping, nil) if err != nil { diff --git a/src/sdk-reference/go/1/collection/update-mapping/index.md b/src/sdk-reference/go/1/collection/update-mapping/index.md index 35c6da474..9783ce623 100644 --- a/src/sdk-reference/go/1/collection/update-mapping/index.md +++ b/src/sdk-reference/go/1/collection/update-mapping/index.md @@ -6,9 +6,13 @@ description: Update the collection mapping # updateMapping -Update the collection mapping. -Mapping allow you to exploit the full capabilities of our -persistent data storage layer, [ElasticSearch](https://www.elastic.co/products/elasticsearch) (check here the [mapping capabilities of ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/reference/5.4/mapping.html)). +Updates a collection mapping. + +{{{since "Kuzzle 1.7.1"}}} + +You can define the collection [dynamic mapping policy]({{ site_base_path}}guide/1/essentials/database-mappings/#dynamic-mapping-policy) by setting the `dynamic` field to the desired value. + +You can define [collection additional metadata]({{ site_base_path}}guide/1/essentials/database-mappings/#collection-metadata) within the `_meta` root field. ## Signature @@ -22,16 +26,19 @@ UpdateMapping(index string, collection string, mapping json.RawMessage, options |--------------|---------|-------------|---------- | ``index`` | string | Index name | yes | | ``collection`` | string | Collection name | yes | -| ``mapping`` | json.RawMessage | Collection data mapping in JSON format | yes | +| ``mapping`` | json.RawMessage | Collection mapping in JSON format | yes | | `options` | QueryOptions | Query options | no | -### **mapping** +### mapping -An string containing the JSON representation of the collection data mapping. +A `json.RawMessage` containing the representation of the collection mapping. -The mapping must have a root field `properties` that contain the mapping definition: ```json { + "dynamic": "[true|false|strict]", + "_meta": { + "field": "value" + }, "properties": { "field1": { "type": "text" }, "field2": { @@ -43,9 +50,9 @@ The mapping must have a root field `properties` that contain the mapping definit } ``` -You can see the full list of Elasticsearch mapping types [here](https://www.elastic.co/guide/en/elasticsearch/reference/5.4/mapping.html). +More informations about database mappings [here]({{ site_base_path}}guide/1/essentials/database-mappings) -### **options** +### options Additional query options diff --git a/src/sdk-reference/go/1/collection/update-mapping/snippets/update-mapping.go b/src/sdk-reference/go/1/collection/update-mapping/snippets/update-mapping.go index fe0dfa683..d701033b2 100644 --- a/src/sdk-reference/go/1/collection/update-mapping/snippets/update-mapping.go +++ b/src/sdk-reference/go/1/collection/update-mapping/snippets/update-mapping.go @@ -1,4 +1,4 @@ -mapping := json.RawMessage(`{"properties":{"plate": {"type": "keyword"}}}`) +mapping := json.RawMessage(`{ "dynamic": "false","_meta": { "area": "Panipokhari" }, "properties":{"plate": {"type": "keyword"}}}`) err := kuzzle.Collection.UpdateMapping("nyc-open-data", "yellow-taxi", mapping, nil) if err != nil { diff --git a/src/sdk-reference/js/6/base-controller/index.md b/src/sdk-reference/js/6/base-controller/index.md new file mode 100644 index 000000000..b4be06abd --- /dev/null +++ b/src/sdk-reference/js/6/base-controller/index.md @@ -0,0 +1,7 @@ +--- +layout: sdk.html.hbs +title: BaseController +description: BaseController object documentation +separator: Core classes +order: 500 +--- diff --git a/src/sdk-reference/js/6/base-controller/introduction/index.md b/src/sdk-reference/js/6/base-controller/introduction/index.md new file mode 100644 index 000000000..8a291676f --- /dev/null +++ b/src/sdk-reference/js/6/base-controller/introduction/index.md @@ -0,0 +1,12 @@ +--- +layout: sdk.html.hbs +title: Introduction +description: BaseController class +order: 0 +--- + +# BaseController + +Base class for a [custom SDK controller]({{ site_base_path }}sdk-reference/js/6/extend-sdk/#define-a-custom-sdk-controller). + +Custom SDK controllers have to extend the `BaseController` class to be added with the [Kuzzle.useController]({{ site_base_path }}sdk-reference/js/6/kuzzle/use-controller) method. diff --git a/src/sdk-reference/js/6/base-controller/properties/index.md b/src/sdk-reference/js/6/base-controller/properties/index.md new file mode 100644 index 000000000..4cab9b314 --- /dev/null +++ b/src/sdk-reference/js/6/base-controller/properties/index.md @@ -0,0 +1,15 @@ +--- +layout: sdk.html.hbs +title: Properties +description: BaseController Properties +--- + +# Properties + +| Property name | Type | Description | +| -------------------- | -------- | --------------------------------------- | +| `name` |
string
| Controller name | +| `kuzzle` |
Kuzzle
| Kuzzle SDK instance | + +**Note:** + - The `name` property will be injected in the request sent by the [BaseController.query]({{ site_base_path }}sdk-reference/js/6/base-controller/query) method if the `controller` property is not set. diff --git a/src/sdk-reference/js/6/base-controller/query/index.md b/src/sdk-reference/js/6/base-controller/query/index.md new file mode 100644 index 000000000..45f8f0438 --- /dev/null +++ b/src/sdk-reference/js/6/base-controller/query/index.md @@ -0,0 +1,54 @@ +--- +layout: sdk.html.hbs +title: query +description: Wrapper around the Kuzzle.query method +--- + +# query + +Base method used to send queries to a Kuzzle controller, following the [API Documentation]({{ site_base_path }}api/1). + +This method injects the controller name into the the request and forwards it to the original [Kuzzle.query]({{ site_base_path }}sdk-reference/js/6/kuzzle/query) method. + +## Arguments + +```javascript +query (request, [options]); +``` + +
+ +| Argument | Type | Description | +| -------------- | --------- | ------------- | +| `request` |
object
| API request | +| `options` |
object
| Optional query options | + +### request + +All properties necessary for the Kuzzle API can be added in the request object. +The following properties are the most common. + +| Property | Type | Description | +| -------------- | --------- | ------------- | +| `action` |
string
| Action name (required) | +| `controller` |
string
| Controller name | +| `body` |
object
| Query body for this action | +| `index` |
string
| Index name for this action | +| `collection` |
string
| Collection name for this action | +| `_id` |
string
| id for this action | +| `volatile` |
object
| Additional information to send to Kuzzle | + +**Note:** + - If the `controller` property is not set, the controller [name property]({{ site_base_path }}sdk-reference/js/6/base-controller/properties) will be used + +### options + +Additional query options + +| Property | Type
(default) | Description | +| -------------- | --------- | ------------- | +| `queuable` |
boolean

(`true`) | If true, queues the request during downtime, until connected to Kuzzle again | + +## Resolves + +Resolve to the raw Kuzzle API response. See the [API Documentation]({{ site_base_path }}api/1). diff --git a/src/sdk-reference/js/6/collection/create/index.md b/src/sdk-reference/js/6/collection/create/index.md index 451347a26..d516649fd 100644 --- a/src/sdk-reference/js/6/collection/create/index.md +++ b/src/sdk-reference/js/6/collection/create/index.md @@ -8,10 +8,17 @@ description: Create a new collection Creates a new [collection]({{ site_base_path }}guide/1/essentials/persisted) in Kuzzle via the persistence engine, in the provided index. -You can also provide an optional data mapping that allow you to exploit the full capabilities of our -persistent data storage layer, [ElasticSearch](https://www.elastic.co/products/elasticsearch) (check here the [mapping capabilities of ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping.html)). +{{{since "Kuzzle 1.3.0"}}} -This method will only update the mapping if the collection already exists. +You can also provide an optional body with a [collection mapping]({{ site_base_path }}guide/1/essentials/database-mappings) that allow you to exploit the full capabilities of our persistent data storage layer. + +This method will only update the mapping when the collection already exists. + +{{{since "Kuzzle 1.7.1"}}} + +You can define the collection [dynamic mapping policy]({{ site_base_path}}guide/1/essentials/database-mappings/#dynamic-mapping-policy) by setting the `dynamic` field to the desired value. + +You can define [collection additional metadata]({{ site_base_path}}guide/1/essentials/database-mappings/#collection-metadata) within the `_meta` root field.
@@ -25,16 +32,19 @@ create (index, collection, [mapping], [options]) |--------------|---------|-------------| | ``index`` |
string
| Index name | | ``collection`` |
string
| Collection name | -| ``mapping`` |
object
| Describes the data mapping to associate to the new collection, using Elasticsearch [mapping format](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping.html) | +| ``mapping`` |
object
| Describes the collection mapping | | ``options`` |
object
| Query options | ### mapping An object representing the data mapping of the collection. -The mapping must have a root field `properties` that contain the mapping definition: ```js const mapping = { + dynamic: '[true|false|strict]', + _meta: { + field: 'value' + }, properties: { field1: { type: 'text' }, field2: { @@ -46,7 +56,7 @@ const mapping = { }; ``` -You can see the full list of Elasticsearch mapping types [here](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping.html). +More informations about database mappings [here]({{ site_base_path}}guide/1/essentials/database-mappings) ### options diff --git a/src/sdk-reference/js/6/collection/create/snippets/create.js b/src/sdk-reference/js/6/collection/create/snippets/create.js index 4c10502d6..f8f143513 100644 --- a/src/sdk-reference/js/6/collection/create/snippets/create.js +++ b/src/sdk-reference/js/6/collection/create/snippets/create.js @@ -1,4 +1,8 @@ const mapping = { + dynamic: 'false', + _meta: { + area: 'Panipokhari' + }, properties: { license: { type: 'keyword' }, driver: { diff --git a/src/sdk-reference/js/6/collection/get-mapping/index.md b/src/sdk-reference/js/6/collection/get-mapping/index.md index 426cfd8f4..035cdcd5c 100644 --- a/src/sdk-reference/js/6/collection/get-mapping/index.md +++ b/src/sdk-reference/js/6/collection/get-mapping/index.md @@ -6,7 +6,7 @@ description: Return collection mapping # getMapping -Returns a collection mapping. +Returns the collection mapping.
diff --git a/src/sdk-reference/js/6/collection/get-mapping/snippets/get-mapping.js b/src/sdk-reference/js/6/collection/get-mapping/snippets/get-mapping.js index 5c1f98d03..d18a7dbc3 100644 --- a/src/sdk-reference/js/6/collection/get-mapping/snippets/get-mapping.js +++ b/src/sdk-reference/js/6/collection/get-mapping/snippets/get-mapping.js @@ -35,4 +35,4 @@ try { console.log('Success'); } catch (error) { console.error(error.message); -} \ No newline at end of file +} diff --git a/src/sdk-reference/js/6/collection/update-mapping/index.md b/src/sdk-reference/js/6/collection/update-mapping/index.md index 09a13ce92..ee604b643 100644 --- a/src/sdk-reference/js/6/collection/update-mapping/index.md +++ b/src/sdk-reference/js/6/collection/update-mapping/index.md @@ -8,6 +8,12 @@ description: Update the collection mapping Updates a collection mapping. +{{{since "Kuzzle 1.7.1"}}} + +You can define the collection [dynamic mapping policy]({{ site_base_path}}guide/1/essentials/database-mappings/#dynamic-mapping-policy) by setting the `dynamic` field to the desired value. + +You can define [collection additional metadata]({{ site_base_path}}guide/1/essentials/database-mappings/#collection-metadata) within the `_meta` root field. +
```javascript @@ -20,28 +26,31 @@ updateMapping (index, collection, mapping, [options]) |--------------|---------|-------------| | ``index`` |
string
| Index name | | ``collection`` |
string
| Collection name | -| ``mapping`` |
object
| Describes the data mapping to associate to the new collection, using Elasticsearch [mapping format](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping.html) | +| ``mapping`` |
object
| Describes the collection mapping | | ``options`` |
object
| Query options | ### mapping -An object representing the collection data mapping. +An object representing the data mapping of the collection. -This object must have a root field `properties` that contain the mapping definition: -```javascript +```js const mapping = { + dynamic: '[true|false|strict]', + _meta: { + field: 'value' + }, properties: { field1: { type: 'text' }, field2: { properties: { - nestedField: { type: 'keyword' } + nestedField: { type: 'keyword'} } } } }; ``` -You can see the full list of Elasticsearch mapping types [here](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping-types.html). +More informations about database mappings [here]({{ site_base_path}}guide/1/essentials/database-mappings) ### options diff --git a/src/sdk-reference/js/6/collection/update-mapping/snippets/update-mapping.js b/src/sdk-reference/js/6/collection/update-mapping/snippets/update-mapping.js index 0f37af87f..d286a6c0a 100644 --- a/src/sdk-reference/js/6/collection/update-mapping/snippets/update-mapping.js +++ b/src/sdk-reference/js/6/collection/update-mapping/snippets/update-mapping.js @@ -1,4 +1,8 @@ const mapping = { + dynamic: 'false', + _meta: { + area: 'Panipokhari' + }, properties: { plate: { type: 'keyword' } } diff --git a/src/sdk-reference/js/6/extend-sdk/index.md b/src/sdk-reference/js/6/extend-sdk/index.md new file mode 100644 index 000000000..adec4e09b --- /dev/null +++ b/src/sdk-reference/js/6/extend-sdk/index.md @@ -0,0 +1,99 @@ +--- +layout: sdk.html.hbs +title: Extends the SDK +description: Extend the SDK +order: 410 +--- + +# Extend the SDK with a custom SDK controller + +It is possible to extend the SDK's API by adding new controllers. + +These controllers correspond to [custom controllers created in a plugin]({{ site_base_path }}plugins/1/essentials/controllers). Thus, it is possible to use the actions of a core plugin in the SDK in the same way as the other actions of the Kuzzle API. + +## Define a custom SDK controller + +A custom SDK controller is a class inheriting from the [BaseController]({{ site_base_path }}sdk-reference/js/6/base-controller) class and defining methods matching Kuzzle API actions. + +This base class is exposed alongside the other classes of the SDK module. + +After defining your new controller based on `BaseController`, you can add it to the SDK with the [Kuzzle.useController]({{ site_base_path }}sdk-reference/js/6/kuzzle/use-controller) method. + +## Constructor + +The constructor of a custom SDK controller will be called by passing the SDK instance to it. It must call the parent constructor with this instance of the SDK and its name as defined in the API. + +For instance, if there is a plugin named `nyc-open-data-taxi`, extending Kuzzle's API with the following controller: + +```javascript +this.controllers = { + taxi: { + startDuty: request => this.startDuty(request) + } +} +``` + +Then the constructor of the custom SDK controller must specify its name as follows (see [how to query a custom API route]({{ site_base_path }}plugins/1/essentials/controllers/#querying-plugins-controllers) documentation): + +```javascript +const { BaseController } = require('kuzzle-sdk'); + +class TaxiController extends BaseController { + constructor (kuzzle) { + super(kuzzle, 'nyc-open-data-plugin/taxi'); + } +} +``` + +The controller name will then be injected into the requests sent with the [BaseController.query]({{ site_base_path }}sdk-reference/js/6/base-controller/query) method. + +## Define custom SDK controller actions + +Each action of your custom SDK controller is a method of the class. + +These methods have to use the [BaseController.query]({{ site_base_path }}sdk-reference/js/6/base-controller/query) method to invoke an API action. + +Extending the previous example, we now have: + +```javascript +const { BaseController } = require('kuzzle-sdk'); + +class TaxiController extends BaseController { + constructor (kuzzle) { + super(kuzzle, 'nyc-open-data-plugin/taxi'); + } + + startDuty (driver) { + const apiRequest = { + action: 'startDuty', + body: { + driver + } + }; + + return this.query(apiRequest) + .then(response => response.result); + } +} +``` + +## Add a custom SDK controller to the SDK + +Once you have defined your custom SDK controller, you can add it to the SDK with the [Kuzzle.useController]({{ site_base_path }}sdk-reference/js/6/kuzzle/use-controller) method. + + +You can then use the actions of your plugins in the same way as the rest of the Kuzzle API by taking advantage of authentication, offline mode management, etc. + +```javascript +const + TaxiController = require('./taxiController'), + { Kuzzle, WebSocket } = require('kuzzle-sdk'); + +const kuzzle = new Kuzzle(new WebSocket('localhost')); + +kuzzle.useController(TaxiController, 'taxi'); + +await kuzzle.connect(); + +await kuzzle.taxi.startDuty('lia meh ry'); +``` diff --git a/src/sdk-reference/js/6/kuzzle/index.md b/src/sdk-reference/js/6/kuzzle/index.md index 2aa7cddfe..372ba8fd1 100644 --- a/src/sdk-reference/js/6/kuzzle/index.md +++ b/src/sdk-reference/js/6/kuzzle/index.md @@ -2,6 +2,5 @@ layout: sdk.html.hbs title: Kuzzle description: Kuzzle object documentation -separator: Core classes -order: 500 +order: 510 --- diff --git a/src/sdk-reference/js/6/kuzzle/query/index.md b/src/sdk-reference/js/6/kuzzle/query/index.md index 658f9c44b..c324c3e8e 100644 --- a/src/sdk-reference/js/6/kuzzle/query/index.md +++ b/src/sdk-reference/js/6/kuzzle/query/index.md @@ -22,7 +22,7 @@ query (request, [options]); | Argument | Type | Description | | -------------- | --------- | ------------- | -| `request` |
object
| API request options | +| `request` |
object
| API request | | `options` |
object
| Optional query options | ### request diff --git a/src/sdk-reference/js/6/kuzzle/use-controller/index.md b/src/sdk-reference/js/6/kuzzle/use-controller/index.md new file mode 100644 index 000000000..f910767c1 --- /dev/null +++ b/src/sdk-reference/js/6/kuzzle/use-controller/index.md @@ -0,0 +1,33 @@ +--- +layout: sdk.html.hbs +title: useController +description: Adds a new controller to the SDK +--- + +# useController + +Adds a new controller to the SDK. + +*See also:* + - *[Extend the SDK]({{ site_base_path }}sdk-reference/js/6/extend-sdk)* + +## Arguments + +```javascript +useController (ControllerClass, accessor); +``` + +
+ +| Argument | Type | Description | +| -------------- | --------- | ------------- | +| `ControllerClass` |
Class
| Controller class. Must inherit from [BaseController]({{ site_base_path }}sdk-reference/js/6/base-controller) | +| `accessor` |
string
| Accessor name for the controller in the Kuzzle object | + +## Returns + +Returns the Kuzzle object. + +## Usage + +[snippet=use-controller] diff --git a/src/sdk-reference/js/6/kuzzle/use-controller/snippets/use-controller.js b/src/sdk-reference/js/6/kuzzle/use-controller/snippets/use-controller.js new file mode 100644 index 000000000..c63c4f286 --- /dev/null +++ b/src/sdk-reference/js/6/kuzzle/use-controller/snippets/use-controller.js @@ -0,0 +1,35 @@ +class TaxiController extends BaseController { + constructor (kuzzle) { + super(kuzzle, 'my-plugin/taxi'); + } + + enroll () { + return this.query({ + action: 'enroll' + }); + } +} + +const kuzzle = new Kuzzle( + new WebSocket('kuzzle') +); + +// Add the custom SDK controller +kuzzle.useController(TaxiController, 'taxi'); + +const run = async () => { + try { + await kuzzle.connect(); + + // Call the custom SDK controller action + console.log(await kuzzle.taxi.enroll()); + + console.log('Success'); + } catch (error) { + console.error(error); + } finally { + kuzzle.disconnect(); + } +}; + +run(); diff --git a/src/sdk-reference/js/6/kuzzle/use-controller/snippets/use-controller.test.yml b/src/sdk-reference/js/6/kuzzle/use-controller/snippets/use-controller.test.yml new file mode 100644 index 000000000..f271472d4 --- /dev/null +++ b/src/sdk-reference/js/6/kuzzle/use-controller/snippets/use-controller.test.yml @@ -0,0 +1,10 @@ +--- +name: kuzzle#useController +description: Adds a new controller to the SDK +hooks: + before: + after: +template: controller +expected: Success +sdk: js +version: 6 diff --git a/test/lib/helpers/logger.js b/test/lib/helpers/logger.js index babc53646..64948de7c 100644 --- a/test/lib/helpers/logger.js +++ b/test/lib/helpers/logger.js @@ -82,7 +82,7 @@ class Logger { console.log(red(' CODE :'), result.code); console.log(red(' FILE :'), result.file); if (result.code === 'ERR_ASSERTION') { - if (result.output.length > 0) { + if (result.output && result.output.length > 0) { console.log(red(' OUTPUT :'), result.output); } console.log(red(' EXPECTED:'), result.expected || snippet.expected); diff --git a/test/templates/controller.tpl.js b/test/templates/controller.tpl.js new file mode 100644 index 000000000..17a2ff24e --- /dev/null +++ b/test/templates/controller.tpl.js @@ -0,0 +1,11 @@ +// load the Kuzzle SDK module +const + { + Kuzzle, + WebSocket, + BaseController + } = require('kuzzle-sdk'); + +BaseController.prototype.query = () => Promise.resolve(null); + +[snippet-code]