From 8a1ca88fc50e68b8bf9f89e147ee1e7f412ec96b Mon Sep 17 00:00:00 2001 From: Alan Plum Date: Tue, 14 Jun 2016 16:58:17 +0200 Subject: [PATCH 01/10] Expand Endpoints docs --- .../Books/Manual/Foxx/Router/Endpoints.mdpp | 328 ++++++++++++++++++ 1 file changed, 328 insertions(+) diff --git a/Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp b/Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp index a9a2782f94..666cdfa7e1 100644 --- a/Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp +++ b/Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp @@ -1,3 +1,331 @@ !CHAPTER Endpoints TODO + +!SECTION header + +`endpoint.header(name, [schema], [description]): this` + +Defines a request header recognized by the endpoint. Any additional non-defined headers will be treated as optional string values. The definitions will also be shown in the route details in the API documentation. + +If the endpoint is a child router, all routes of that router will use this header definition unless overridden. If the endpoint is a middleware, this method has no effect. + + +**Arguments** + +* **name**: `string` + + TODO + +* **schema**: `Schema` (optional) + + TODO + +* **description**: `string` (optional) + + TODO + +Returns the endpoint. + +**Examples** + +```js +router.get(/* ... */) +.header('arangoVersion', joi.number().min(30000).default(30000)); +``` + +!SECTION pathParam + +`endpoint.pathParam(name, [schema], [description]): this` + +Defines a path parameter recognized by the endpoint. Path parameters are expected to be filled as part of the endpoint's mount path. Any additional non-defined path parameters will be treated as optional string values. The definitions will also be shown in the route details in the API documentation. + +If the endpoint is a child router, all routes of that router will use this header definition unless overridden. If the endpoint is a middleware, this method has no effect. + +**Arguments** + +* **name**: `string` + + TODO + +* **schema**: `Schema` (optional) + + TODO + +* **description**: `string` (optional) + + TODO + +Returns the endpoint. + +**Examples** + +```js +router.get('/some/:num/here', /* ... */) +.pathParam('num', joi.number().required()); +``` + +!SECTION queryParam + +`endpoint.queryParam(name, [schema], [description]): this` + +Defines a query parameter recognized by the endpoint. Any additional non-defined query parameters will be treated as optional string values. The definitions will also be shown in the route details in the API documentation. + +If the endpoint is a child router, all routes of that router will use this header definition unless overridden. If the endpoint is a middleware, this method has no effect. + +**Arguments** + +* **name**: `string` + + TODO + +* **schema**: `Schema` (optional) + + TODO + +* **description**: `string` (optional) + + TODO + +Returns the endpoint. + +**Examples** + +```js +``` + +!SECTION body + +`endpoint.body([model], [mimes], [description]): this` + +TODO + +**Arguments** + +* **model**: `Model | Schema` (optional) + + TODO + +* **mimes**: `Array` (optional) + + TODO + +* **description**: `string` (optional) + + TODO + +Returns the endpoint. + +**Examples** + +```js +router.post('/expects/some/json', /* ... */) +.body( + joi.object().required(), + 'This implies JSON.' +); + +router.post('/expects/some/plaintext', /* ... */) +.body(['text/plain'], 'This body will be a string.'); +``` + +!SECTION response + +`endpoint.response([status], [model], [mimes], [description]): this` + +Defines a response body for the endpoint. When using the response object's `send` method in the request handler of this route, the definition with the matching status code will be used to generate the response body. The definitions will also be shown in the route details in the API documentation. + +If the endpoint is a child router, all routes of that router will use this response definition unless overridden. If the endpoint is a middleware, this method has no effect. + +**Arguments** + +* **status**: `number | string` (Default: `200` or `204`) + + HTTP status code the response applies to. If a string is provided instead of a numeric status code it will be used to look up a numeric status code using the [statuses][STATUSES] module. + +* **model**: `Model | Schema | null` (optional) + + A model or joi schema describing the response body. + + If the value is a model with a `forClient` method, that method will be applied to the data passed to `response.send` within the route if the response status code matches (but also if no status code has been set). + + If the value is a schema or a model with a schema, the actual schema will not be used to validate the response body and only serves to document the response in more detail in the API documentation. + + If the value is a model or a schema and the mime type has been omitted, the mime type will default to JSON instead. + + If the value is explicitly set to `null` and the status code has been omitted, the status code will default to `204` ("no content") instead of `200`. + + If the value is an array containing exactly one model or schema, the response body will be an array of items matching that model or schema. + +* **mimes**: `Array` (optional) + + An array of mime types the route might respond with for this status code. + + Common non-mime aliases like "json" or "html" are also supported and will be expanded to the appropriate mime type (e.g. "application/json" and "text/html"). + + When using the `response.send` method the response body will be converted to the appropriate mime type if possible. + +* **description**: `string` (optional) + + A human-readable string that briefly describes the response and will be shown in the endpoint's detailed documentation. + +Returns the endpoint. + +**Examples** + +```js +// This example only provides documentation +// and implies a generic JSON response body. +router.get(/* ... */) +.response( + joi.array().items(joi.string()), + 'A list of doodad identifiers.' +); + +// No response body will be expected here. +router.delete(/* ... */) +.response(null, 'The doodad no longer exists.'); + +// An endpoint can define multiple response types +// for different status codes -- but never more than +// one for each status code. +router.post(/* ... */) +.response('found', 'The doodad is located elsewhere.') +.response(201, ['text/plain'], 'The doodad was created so here is a haiku.'); + +// Here the response body will be set to +// the querystring-encoded result of +// FormModel.forClient({some: 'data'}) +// because the status code defaults to 200. +router.patch(function (req, res) { + // ... + res.send({some: 'data'}); +}) +.response(FormModel, ['application/x-www-form-urlencoded'], 'OMG.'); + +// In this case the response body will be set to +// SomeModel.forClient({some: 'data'}) because +// the status code has been set to 201 before. +router.put(function (req, res) { + // ... + res.status(201); + res.send({some: 'data'}); +}) +.response(201, SomeModel, 'Something amazing happened.'); +``` + +!SECTION error + +`endpoint.error(status, [description]): this` + +Documents an error status for the endpoint. + +If the endpoint is a child router, all routes of that router will use this error description unless overridden. If the endpoint is a middleware, this method has no effect. + +This method only affects the generated API documentation and has not other effect within the service itself. + +**Arguments** + +* **status**: `number | string` + + HTTP status code for the error (e.g. `400` for "bad request"). If a string is provided instead of a numeric status code it will be used to look up a numeric status code using the [statuses][STATUSES] module. + +* **description**: `string` (optional) + + A human-readable string that briefly describes the error condition and will be shown in the endpoint's detailed documentation. + +Returns the endpoint. + +**Examples** + +```js +router.get(function (req, res) { + // ... + res.throw(403, 'Validation error at x.y.z'); +}) +.error(403, 'Indicates that a validation has failed.'); +``` + +!SECTION summary + +`endpoint.summary(summary): this` + +Adds a short description to the endpoint's API documentation. + +If the endpoint is a child router, all routes of that router will use this summary unless overridden. If the endpoint is a middleware, this method has no effect. + +This method only affects the generated API documentation and has not other effect within the service itself. + +**Arguments** + +* **summary**: `string` + + A human-readable string that briefly describes the endpoint and will appear next to the endpoint's path in the documentation. + +Returns the endpoint. + +**Examples** + +```js +router.get(/* ... */) +.summary('List all discombobulated doodads') +``` + +!SECTION description + +`endpoint.description(description): this` + +Adds a long description to the endpoint's API documentation. + +If the endpoint is a child router, all routes of that router will use this description unless overridden. If the endpoint is a middleware, this method has no effect. + +This method only affects the generated API documentation and has not other effect within the service itself. + +**Arguments** + +* **description**: `string` + + A human-readable string that describes the endpoint in detail and will be shown in the endpoint's detailed documentation. + +Returns the endpoint. + +**Examples** + +```js +// The "dedent" library helps formatting +// multi-line strings by adjusting indentation +// and removing leading and trailing blank lines +const dd = require('dedent'); +router.post(/* ... */) +.description(dd` + This route discombobulates the doodads by + frobnicating the moxie of the request body. +`) +``` + +!SECTION deprecated + +`endpoint.deprecated([deprecated]): this` + +Marks the endpoint as deprecated. + +If the endpoint is a child router, all routes of that router will also be marked as deprecated. If the endpoint is a middleware, this method has no effect. + +This method only affects the generated API documentation and has not other effect within the service itself. + +**Arguments** + +* **deprecated**: `boolean` (Default: `true`) + + Whether the endpoint should be marked as deprecated. If set to `false` the endpoint will be explicitly marked as *not* deprecated. + +Returns the endpoint. + +**Examples** + +```js +router.get(/* ... */) +.deprecated(); +``` + +[STATUSES]: https://github.com/jshttp/statuses From 1b826e9292efc034e9485368094b50332af29953 Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Tue, 14 Jun 2016 17:13:28 +0200 Subject: [PATCH 02/10] Fix more dead links. --- Documentation/Books/Manual/GettingStarted/Authentication.mdpp | 2 +- Documentation/Books/Manual/Graphs/README.mdpp | 2 +- Documentation/DocuBlocks/Rest/AQL/JSF_post_api_explain.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/Books/Manual/GettingStarted/Authentication.mdpp b/Documentation/Books/Manual/GettingStarted/Authentication.mdpp index d58ec0805e..f2fc5ec132 100644 --- a/Documentation/Books/Manual/GettingStarted/Authentication.mdpp +++ b/Documentation/Books/Manual/GettingStarted/Authentication.mdpp @@ -7,7 +7,7 @@ all databases. You should create a database for your application together with a user that has access rights to this database. See -[Managing Users](../Administration/ManagingUsers/index.html). +[Managing Users](../Administration/ManagingUsers.md). Use the *arangosh* to create a new database and user. diff --git a/Documentation/Books/Manual/Graphs/README.mdpp b/Documentation/Books/Manual/Graphs/README.mdpp index 813b574ab9..71ebd759f2 100644 --- a/Documentation/Books/Manual/Graphs/README.mdpp +++ b/Documentation/Books/Manual/Graphs/README.mdpp @@ -45,7 +45,7 @@ so if you delete documents from your vertex collections directly, the edges poin !SUBSECTION Anonymous graphs Sometimes you may not need all the powers of named graphs, but some of its bits may be valuable to you. -You [may use AQL Graph Functions](../../AQL/Graphs/Functions.html) that are a little deeper explained in the [traversals](Traversals/README.md) and the [Working with Edges](Edges/README.md) chapter. +You may use anonymous graphs in the [traversals](Traversals/README.md) and in the [Working with Edges](Edges/README.md) chapter. Anonymous graphs don't have *edge definitions* describing which *vertex collection* is connected by which *edge collection*. The graph model has to be maintained in the client side code. This gives you more freedom than the strict *named graphs*. diff --git a/Documentation/DocuBlocks/Rest/AQL/JSF_post_api_explain.md b/Documentation/DocuBlocks/Rest/AQL/JSF_post_api_explain.md index c254fdbdee..8ab4657ea9 100644 --- a/Documentation/DocuBlocks/Rest/AQL/JSF_post_api_explain.md +++ b/Documentation/DocuBlocks/Rest/AQL/JSF_post_api_explain.md @@ -62,7 +62,7 @@ is set to *true*. Each plan in the result is a JSON object with the following attributes: - *nodes*: the array of execution nodes of the plan. The array of available node types - can be found [here](../../AQL/Optimizer.html) + can be found [here](../../AQL/ExecutionAndPerformance/Optimizer.html) - *estimatedCost*: the total estimated cost for the plan. If there are multiple plans, the optimizer will choose the plan with the lowest total cost. @@ -70,7 +70,7 @@ Each plan in the result is a JSON object with the following attributes: - *collections*: an array of collections used in the query - *rules*: an array of rules the optimizer applied. An overview of the - available rules can be found [here](../../AQL/Optimizer.html) + available rules can be found [here](../../AQL/ExecutionAndPerformance/Optimizer.html) - *variables*: array of variables used in the query (note: this may contain internal variables created by the optimizer) From 0f66a110de7537dfcf5934c78a17ea0009cdfefd Mon Sep 17 00:00:00 2001 From: Kaveh Vahedipour Date: Tue, 14 Jun 2016 17:13:52 +0200 Subject: [PATCH 03/10] fixed max_elements bug in job transactions --- arangod/Agency/Job.h | 2 +- arangod/Agency/RestAgencyHandler.cpp | 2 +- js/client/tests/agency/agency-test.js | 9 +++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/arangod/Agency/Job.h b/arangod/Agency/Job.h index d2e4c738b6..aa623de80d 100644 --- a/arangod/Agency/Job.h +++ b/arangod/Agency/Job.h @@ -69,7 +69,7 @@ inline arangodb::consensus::write_ret_t transact ( LOG_TOPIC(DEBUG, Logger::AGENCY) << envelope->toJson(); auto ret = _agent->write(envelope); - if (waitForCommit) { + if (waitForCommit && !ret.indices.empty()) { auto maximum = *std::max_element(ret.indices.begin(), ret.indices.end()); if (maximum > 0) { // some baby has worked _agent->waitFor(maximum); diff --git a/arangod/Agency/RestAgencyHandler.cpp b/arangod/Agency/RestAgencyHandler.cpp index 4baab22446..8a89f9262c 100644 --- a/arangod/Agency/RestAgencyHandler.cpp +++ b/arangod/Agency/RestAgencyHandler.cpp @@ -173,7 +173,7 @@ HttpHandler::status_t RestAgencyHandler::handleWrite() { } catch (std::exception const& e) { LOG_TOPIC(WARN, Logger::AGENCY) << e.what(); } - std::this_thread::sleep_for(duration_t(5)); + std::this_thread::sleep_for(duration_t(2)); if (max_index > 0) { _agent->waitFor(max_index); } diff --git a/js/client/tests/agency/agency-test.js b/js/client/tests/agency/agency-test.js index c9210020fd..889154b197 100644 --- a/js/client/tests/agency/agency-test.js +++ b/js/client/tests/agency/agency-test.js @@ -467,11 +467,12 @@ function agencyTestSuite () { writeAndCheck([[{"////////////////////////": "Hi there!"}]]); assertEqual(readAndCheck([["/"]]), ["Hi there!"]); writeAndCheck([[{"/":{"op":"delete"}}]]); - writeAndCheck([[{"/////////////////\/////a/////////////////////b\//": {"b///////\c":4}}]]); + writeAndCheck( + [[{"/////////////////\\/////a/////////////^&%^&$^&%$////////b\\\n//": + {"b///////c":4}}]]); + assertEqual(readAndCheck([["/"]]), + [{"\\":{"a":{"^&%^&$^&%$":{"b\\\n":{"b":{"c":4}}}}}}]); } - - - }; } From 98f3258eef2c17ed4fa406ae78732d662999e16c Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Tue, 14 Jun 2016 17:13:53 +0200 Subject: [PATCH 04/10] fresh swagger. --- js/apps/system/_admin/aardvark/APP/api-docs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/apps/system/_admin/aardvark/APP/api-docs.json b/js/apps/system/_admin/aardvark/APP/api-docs.json index fd0a008621..18505d7b2a 100644 --- a/js/apps/system/_admin/aardvark/APP/api-docs.json +++ b/js/apps/system/_admin/aardvark/APP/api-docs.json @@ -4068,7 +4068,7 @@ }, "/_api/explain": { "post": { - "description": "**A json post document with these Properties is required:**\n\n - **query**: the query which you want explained; If the query references any bind variables,\n these must also be passed in the attribute *bindVars*. Additional\n options for the query can be passed in the *options* attribute.\n - **options**:\n - **optimizer.rules**: an array of to-be-included or to-be-excluded optimizer rules\n can be put into this attribute, telling the optimizer to include or exclude\n specific rules. To disable a rule, prefix its name with a `-`, to enable a rule, prefix it\n with a `+`. There is also a pseudo-rule `all`, which will match all optimizer rules. of type string\n - **maxNumberOfPlans**: an optional maximum number of plans that the optimizer is \n allowed to generate. Setting this attribute to a low value allows to put a\n cap on the amount of work the optimizer does.\n - **allPlans**: if set to *true*, all possible execution plans will be returned.\n The default is *false*, meaning only the optimal plan will be returned.\n - **bindVars**: key/value pairs representing the bind values of type object\n\n\n\n\n\nTo explain how an AQL query would be executed on the server, the query string\ncan be sent to the server via an HTTP POST request. The server will then validate\nthe query and create an execution plan for it. The execution plan will be\nreturned, but the query will not be executed.\n\nThe execution plan that is returned by the server can be used to estimate the\nprobable performance of the query. Though the actual performance will depend\non many different factors, the execution plan normally can provide some rough\nestimates on the amount of work the server needs to do in order to actually run \nthe query.\n\nBy default, the explain operation will return the optimal plan as chosen by\nthe query optimizer The optimal plan is the plan with the lowest total estimated\ncost. The plan will be returned in the attribute *plan* of the response object.\nIf the option *allPlans* is specified in the request, the result will contain \nall plans created by the optimizer. The plans will then be returned in the \nattribute *plans*.\n\nThe result will also contain an attribute *warnings*, which is an array of \nwarnings that occurred during optimization or execution plan creation. Additionally,\na *stats* attribute is contained in the result with some optimizer statistics.\nIf *allPlans* is set to *false*, the result will contain an attribute *cacheable* \nthat states whether the query results can be cached on the server if the query\nresult cache were used. The *cacheable* attribute is not present when *allPlans*\nis set to *true*.\n\nEach plan in the result is a JSON object with the following attributes:\n- *nodes*: the array of execution nodes of the plan. The array of available node types\n can be found [here](../../AQL/Optimizer.html)\n\n- *estimatedCost*: the total estimated cost for the plan. If there are multiple\n plans, the optimizer will choose the plan with the lowest total cost.\n\n- *collections*: an array of collections used in the query\n\n- *rules*: an array of rules the optimizer applied. An overview of the\n available rules can be found [here](../../AQL/Optimizer.html)\n\n- *variables*: array of variables used in the query (note: this may contain\n internal variables created by the optimizer)\n\n\n\n\n#Example:\n Valid query\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \n  \"query\" : \"FOR p IN products RETURN p\" \n}\nEOF\n\nHTTP/1.1 200 OK\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"plan\" : { \n    \"nodes\" : [ \n      { \n        \"type\" : \"SingletonNode\", \n        \"dependencies\" : [ ], \n        \"id\" : 1, \n        \"estimatedCost\" : 1, \n        \"estimatedNrItems\" : 1 \n      }, \n      { \n        \"type\" : \"EnumerateCollectionNode\", \n        \"dependencies\" : [ \n          1 \n        ], \n        \"id\" : 2, \n        \"estimatedCost\" : 11, \n        \"estimatedNrItems\" : 10, \n        \"database\" : \"_system\", \n        \"collection\" : \"products\", \n        \"outVariable\" : { \n          \"id\" : 0, \n          \"name\" : \"p\" \n        }, \n        \"random\" : false \n      }, \n      { \n        \"type\" : \"ReturnNode\", \n        \"dependencies\" : [ \n          2 \n        ], \n        \"id\" : 3, \n        \"estimatedCost\" : 21, \n        \"estimatedNrItems\" : 10, \n        \"inVariable\" : { \n          \"id\" : 0, \n          \"name\" : \"p\" \n        } \n      } \n    ], \n    \"rules\" : [ ], \n    \"collections\" : [ \n      { \n        \"name\" : \"products\", \n        \"type\" : \"read\" \n      } \n    ], \n    \"variables\" : [ \n      { \n        \"id\" : 0, \n        \"name\" : \"p\" \n      } \n    ], \n    \"estimatedCost\" : 21, \n    \"estimatedNrItems\" : 10 \n  }, \n  \"warnings\" : [ ], \n  \"stats\" : { \n    \"rulesExecuted\" : 26, \n    \"rulesSkipped\" : 0, \n    \"plansCreated\" : 1 \n  }, \n  \"cacheable\" : true, \n  \"error\" : false, \n  \"code\" : 200 \n}\n
\n\n\n\n\n#Example:\n A plan with some optimizer rules applied\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \n  \"query\" : \"FOR p IN products LET a = p.id FILTER a == 4 LET name = p.name SORT p.id LIMIT 1 RETURN name\" \n}\nEOF\n\nHTTP/1.1 200 OK\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"plan\" : { \n    \"nodes\" : [ \n      { \n        \"type\" : \"SingletonNode\", \n        \"dependencies\" : [ ], \n        \"id\" : 1, \n        \"estimatedCost\" : 1, \n        \"estimatedNrItems\" : 1 \n      }, \n      { \n        \"type\" : \"IndexNode\", \n        \"dependencies\" : [ \n          1 \n        ], \n        \"id\" : 11, \n        \"estimatedCost\" : 11, \n        \"estimatedNrItems\" : 10, \n        \"database\" : \"_system\", \n        \"collection\" : \"products\", \n        \"outVariable\" : { \n          \"id\" : 0, \n          \"name\" : \"p\" \n        }, \n        \"indexes\" : [ \n          { \n            \"id\" : \"10551\", \n            \"type\" : \"skiplist\", \n            \"fields\" : [ \n              \"id\" \n            ], \n            \"unique\" : false, \n            \"sparse\" : false \n          } \n        ], \n        \"condition\" : { \n        }, \n        \"reverse\" : false \n      }, \n      { \n        \"type\" : \"CalculationNode\", \n        \"dependencies\" : [ \n          11 \n        ], \n        \"id\" : 4, \n        \"estimatedCost\" : 21, \n        \"estimatedNrItems\" : 10, \n        \"expression\" : { \n          \"type\" : \"compare ==\", \n          \"subNodes\" : [ \n            { \n              \"type\" : \"attribute access\", \n              \"name\" : \"id\", \n              \"subNodes\" : [ \n                { \n                  \"type\" : \"reference\", \n                  \"name\" : \"p\", \n                  \"id\" : 0 \n                } \n              ] \n            }, \n            { \n              \"type\" : \"value\", \n              \"value\" : 4 \n            } \n          ] \n        }, \n        \"outVariable\" : { \n          \"id\" : 4, \n          \"name\" : \"3\" \n        }, \n        \"canThrow\" : false, \n        \"expressionType\" : \"simple\" \n      }, \n      { \n        \"type\" : \"FilterNode\", \n        \"dependencies\" : [ \n          4 \n        ], \n        \"id\" : 5, \n        \"estimatedCost\" : 31, \n        \"estimatedNrItems\" : 10, \n        \"inVariable\" : { \n          \"id\" : 4, \n          \"name\" : \"3\" \n        } \n      }, \n      { \n        \"type\" : \"LimitNode\", \n        \"dependencies\" : [ \n          5 \n        ], \n        \"id\" : 9, \n        \"estimatedCost\" : 32, \n        \"estimatedNrItems\" : 1, \n        \"offset\" : 0, \n        \"limit\" : 1, \n        \"fullCount\" : false \n      }, \n      { \n        \"type\" : \"CalculationNode\", \n        \"dependencies\" : [ \n          9 \n        ], \n        \"id\" : 6, \n        \"estimatedCost\" : 33, \n        \"estimatedNrItems\" : 1, \n        \"expression\" : { \n          \"type\" : \"attribute access\", \n          \"name\" : \"name\", \n          \"subNodes\" : [ \n            { \n              \"type\" : \"reference\", \n              \"name\" : \"p\", \n              \"id\" : 0 \n            } \n          ] \n        }, \n        \"outVariable\" : { \n          \"id\" : 2, \n          \"name\" : \"name\" \n        }, \n        \"canThrow\" : false, \n        \"expressionType\" : \"attribute\" \n      }, \n      { \n        \"type\" : \"ReturnNode\", \n        \"dependencies\" : [ \n          6 \n        ], \n        \"id\" : 10, \n        \"estimatedCost\" : 34, \n        \"estimatedNrItems\" : 1, \n        \"inVariable\" : { \n          \"id\" : 2, \n          \"name\" : \"name\" \n        } \n      } \n    ], \n    \"rules\" : [ \n      \"move-calculations-up\", \n      \"remove-redundant-calculations\", \n      \"remove-unnecessary-calculations\", \n      \"move-calculations-up-2\", \n      \"use-index-for-sort\", \n      \"remove-unnecessary-calculations-2\", \n      \"move-calculations-down\" \n    ], \n    \"collections\" : [ \n      { \n        \"name\" : \"products\", \n        \"type\" : \"read\" \n      } \n    ], \n    \"variables\" : [ \n      { \n        \"id\" : 6, \n        \"name\" : \"5\" \n      }, \n      { \n        \"id\" : 4, \n        \"name\" : \"3\" \n      }, \n      { \n        \"id\" : 2, \n        \"name\" : \"name\" \n      }, \n      { \n        \"id\" : 1, \n        \"name\" : \"a\" \n      }, \n      { \n        \"id\" : 0, \n        \"name\" : \"p\" \n      } \n    ], \n    \"estimatedCost\" : 34, \n    \"estimatedNrItems\" : 1 \n  }, \n  \"warnings\" : [ ], \n  \"stats\" : { \n    \"rulesExecuted\" : 26, \n    \"rulesSkipped\" : 0, \n    \"plansCreated\" : 1 \n  }, \n  \"cacheable\" : true, \n  \"error\" : false, \n  \"code\" : 200 \n}\n
\n\n\n\n\n#Example:\n Using some options\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \n  \"query\" : \"FOR p IN products LET a = p.id FILTER a == 4 LET name = p.name SORT p.id LIMIT 1 RETURN name\", \n  \"options\" : { \n    \"maxNumberOfPlans\" : 2, \n    \"allPlans\" : true, \n    \"optimizer\" : { \n      \"rules\" : [ \n        \"-all\", \n        \"+use-index-for-sort\", \n        \"+use-index-range\" \n      ] \n    } \n  } \n}\nEOF\n\nHTTP/1.1 200 OK\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"plans\" : [ \n    { \n      \"nodes\" : [ \n        { \n          \"type\" : \"SingletonNode\", \n          \"dependencies\" : [ ], \n          \"id\" : 1, \n          \"estimatedCost\" : 1, \n          \"estimatedNrItems\" : 1 \n        }, \n        { \n          \"type\" : \"IndexNode\", \n          \"dependencies\" : [ \n            1 \n          ], \n          \"id\" : 11, \n          \"estimatedCost\" : 11, \n          \"estimatedNrItems\" : 10, \n          \"database\" : \"_system\", \n          \"collection\" : \"products\", \n          \"outVariable\" : { \n            \"id\" : 0, \n            \"name\" : \"p\" \n          }, \n          \"indexes\" : [ \n            { \n              \"id\" : \"10589\", \n              \"type\" : \"skiplist\", \n              \"fields\" : [ \n                \"id\" \n              ], \n              \"unique\" : false, \n              \"sparse\" : false \n            } \n          ], \n          \"condition\" : { \n          }, \n          \"reverse\" : false \n        }, \n        { \n          \"type\" : \"CalculationNode\", \n          \"dependencies\" : [ \n            11 \n          ], \n          \"id\" : 3, \n          \"estimatedCost\" : 21, \n          \"estimatedNrItems\" : 10, \n          \"expression\" : { \n            \"type\" : \"attribute access\", \n            \"name\" : \"id\", \n            \"subNodes\" : [ \n              { \n                \"type\" : \"reference\", \n                \"name\" : \"p\", \n                \"id\" : 0 \n              } \n            ] \n          }, \n          \"outVariable\" : { \n            \"id\" : 1, \n            \"name\" : \"a\" \n          }, \n          \"canThrow\" : false, \n          \"expressionType\" : \"attribute\" \n        }, \n        { \n          \"type\" : \"CalculationNode\", \n          \"dependencies\" : [ \n            3 \n          ], \n          \"id\" : 4, \n          \"estimatedCost\" : 31, \n          \"estimatedNrItems\" : 10, \n          \"expression\" : { \n            \"type\" : \"compare ==\", \n            \"subNodes\" : [ \n              { \n                \"type\" : \"reference\", \n                \"name\" : \"a\", \n                \"id\" : 1 \n              }, \n              { \n                \"type\" : \"value\", \n                \"value\" : 4 \n              } \n            ] \n          }, \n          \"outVariable\" : { \n            \"id\" : 4, \n            \"name\" : \"3\" \n          }, \n          \"canThrow\" : false, \n          \"expressionType\" : \"simple\" \n        }, \n        { \n          \"type\" : \"FilterNode\", \n          \"dependencies\" : [ \n            4 \n          ], \n          \"id\" : 5, \n          \"estimatedCost\" : 41, \n          \"estimatedNrItems\" : 10, \n          \"inVariable\" : { \n            \"id\" : 4, \n            \"name\" : \"3\" \n          } \n        }, \n        { \n          \"type\" : \"CalculationNode\", \n          \"dependencies\" : [ \n            5 \n          ], \n          \"id\" : 6, \n          \"estimatedCost\" : 51, \n          \"estimatedNrItems\" : 10, \n          \"expression\" : { \n            \"type\" : \"attribute access\", \n            \"name\" : \"name\", \n            \"subNodes\" : [ \n              { \n                \"type\" : \"reference\", \n                \"name\" : \"p\", \n                \"id\" : 0 \n              } \n            ] \n          }, \n          \"outVariable\" : { \n            \"id\" : 2, \n            \"name\" : \"name\" \n          }, \n          \"canThrow\" : false, \n          \"expressionType\" : \"attribute\" \n        }, \n        { \n          \"type\" : \"CalculationNode\", \n          \"dependencies\" : [ \n            6 \n          ], \n          \"id\" : 7, \n          \"estimatedCost\" : 61, \n          \"estimatedNrItems\" : 10, \n          \"expression\" : { \n            \"type\" : \"attribute access\", \n            \"name\" : \"id\", \n            \"subNodes\" : [ \n              { \n                \"type\" : \"reference\", \n                \"name\" : \"p\", \n                \"id\" : 0 \n              } \n            ] \n          }, \n          \"outVariable\" : { \n            \"id\" : 6, \n            \"name\" : \"5\" \n          }, \n          \"canThrow\" : false, \n          \"expressionType\" : \"attribute\" \n        }, \n        { \n          \"type\" : \"LimitNode\", \n          \"dependencies\" : [ \n            7 \n          ], \n          \"id\" : 9, \n          \"estimatedCost\" : 62, \n          \"estimatedNrItems\" : 1, \n          \"offset\" : 0, \n          \"limit\" : 1, \n          \"fullCount\" : false \n        }, \n        { \n          \"type\" : \"ReturnNode\", \n          \"dependencies\" : [ \n            9 \n          ], \n          \"id\" : 10, \n          \"estimatedCost\" : 63, \n          \"estimatedNrItems\" : 1, \n          \"inVariable\" : { \n            \"id\" : 2, \n            \"name\" : \"name\" \n          } \n        } \n      ], \n      \"rules\" : [ \n        \"use-index-for-sort\" \n      ], \n      \"collections\" : [ \n        { \n          \"name\" : \"products\", \n          \"type\" : \"read\" \n        } \n      ], \n      \"variables\" : [ \n        { \n          \"id\" : 6, \n          \"name\" : \"5\" \n        }, \n        { \n          \"id\" : 4, \n          \"name\" : \"3\" \n        }, \n        { \n          \"id\" : 2, \n          \"name\" : \"name\" \n        }, \n        { \n          \"id\" : 1, \n          \"name\" : \"a\" \n        }, \n        { \n          \"id\" : 0, \n          \"name\" : \"p\" \n        } \n      ], \n      \"estimatedCost\" : 63, \n      \"estimatedNrItems\" : 1 \n    } \n  ], \n  \"warnings\" : [ ], \n  \"stats\" : { \n    \"rulesExecuted\" : 1, \n    \"rulesSkipped\" : 25, \n    \"plansCreated\" : 1 \n  }, \n  \"error\" : false, \n  \"code\" : 200 \n}\n
\n\n\n\n\n#Example:\n Returning all plans\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \n  \"query\" : \"FOR p IN products FILTER p.id == 25 RETURN p\", \n  \"options\" : { \n    \"allPlans\" : true \n  } \n}\nEOF\n\nHTTP/1.1 200 OK\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"plans\" : [ \n    { \n      \"nodes\" : [ \n        { \n          \"type\" : \"SingletonNode\", \n          \"dependencies\" : [ ], \n          \"id\" : 1, \n          \"estimatedCost\" : 1, \n          \"estimatedNrItems\" : 1 \n        }, \n        { \n          \"type\" : \"IndexNode\", \n          \"dependencies\" : [ \n            1 \n          ], \n          \"id\" : 6, \n          \"estimatedCost\" : 1.99, \n          \"estimatedNrItems\" : 1, \n          \"database\" : \"_system\", \n          \"collection\" : \"products\", \n          \"outVariable\" : { \n            \"id\" : 0, \n            \"name\" : \"p\" \n          }, \n          \"indexes\" : [ \n            { \n              \"id\" : \"10537\", \n              \"type\" : \"hash\", \n              \"fields\" : [ \n                \"id\" \n              ], \n              \"selectivityEstimate\" : 1, \n              \"unique\" : false, \n              \"sparse\" : false \n            } \n          ], \n          \"condition\" : { \n            \"type\" : \"n-ary or\", \n            \"subNodes\" : [ \n              { \n                \"type\" : \"n-ary and\", \n                \"subNodes\" : [ \n                  { \n                    \"type\" : \"compare ==\", \n                    \"subNodes\" : [ \n                      { \n                        \"type\" : \"attribute access\", \n                        \"name\" : \"id\", \n                        \"subNodes\" : [ \n                          { \n                            \"type\" : \"reference\", \n                            \"name\" : \"p\", \n                            \"id\" : 0 \n                          } \n                        ] \n                      }, \n                      { \n                        \"type\" : \"value\", \n                        \"value\" : 25 \n                      } \n                    ] \n                  } \n                ] \n              } \n            ] \n          }, \n          \"reverse\" : false \n        }, \n        { \n          \"type\" : \"ReturnNode\", \n          \"dependencies\" : [ \n            6 \n          ], \n          \"id\" : 5, \n          \"estimatedCost\" : 2.99, \n          \"estimatedNrItems\" : 1, \n          \"inVariable\" : { \n            \"id\" : 0, \n            \"name\" : \"p\" \n          } \n        } \n      ], \n      \"rules\" : [ \n        \"use-indexes\", \n        \"remove-filter-covered-by-index\" \n      ], \n      \"collections\" : [ \n        { \n          \"name\" : \"products\", \n          \"type\" : \"read\" \n        } \n      ], \n      \"variables\" : [ \n        { \n          \"id\" : 2, \n          \"name\" : \"1\" \n        }, \n        { \n          \"id\" : 0, \n          \"name\" : \"p\" \n        } \n      ], \n      \"estimatedCost\" : 2.99, \n      \"estimatedNrItems\" : 1 \n    } \n  ], \n  \"warnings\" : [ ], \n  \"stats\" : { \n    \"rulesExecuted\" : 26, \n    \"rulesSkipped\" : 0, \n    \"plansCreated\" : 1 \n  }, \n  \"error\" : false, \n  \"code\" : 200 \n}\n
\n\n\n\n\n#Example:\n A query that produces a warning\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \n  \"query\" : \"FOR i IN 1..10 RETURN 1 / 0\" \n}\nEOF\n\nHTTP/1.1 200 OK\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"plan\" : { \n    \"nodes\" : [ \n      { \n        \"type\" : \"SingletonNode\", \n        \"dependencies\" : [ ], \n        \"id\" : 1, \n        \"estimatedCost\" : 1, \n        \"estimatedNrItems\" : 1 \n      }, \n      { \n        \"type\" : \"CalculationNode\", \n        \"dependencies\" : [ \n          1 \n        ], \n        \"id\" : 2, \n        \"estimatedCost\" : 2, \n        \"estimatedNrItems\" : 1, \n        \"expression\" : { \n          \"type\" : \"range\", \n          \"subNodes\" : [ \n            { \n              \"type\" : \"value\", \n              \"value\" : 1 \n            }, \n            { \n              \"type\" : \"value\", \n              \"value\" : 10 \n            } \n          ] \n        }, \n        \"outVariable\" : { \n          \"id\" : 2, \n          \"name\" : \"1\" \n        }, \n        \"canThrow\" : false, \n        \"expressionType\" : \"simple\" \n      }, \n      { \n        \"type\" : \"CalculationNode\", \n        \"dependencies\" : [ \n          2 \n        ], \n        \"id\" : 4, \n        \"estimatedCost\" : 3, \n        \"estimatedNrItems\" : 1, \n        \"expression\" : { \n          \"type\" : \"value\", \n          \"value\" : null \n        }, \n        \"outVariable\" : { \n          \"id\" : 4, \n          \"name\" : \"3\" \n        }, \n        \"canThrow\" : false, \n        \"expressionType\" : \"json\" \n      }, \n      { \n        \"type\" : \"EnumerateListNode\", \n        \"dependencies\" : [ \n          4 \n        ], \n        \"id\" : 3, \n        \"estimatedCost\" : 13, \n        \"estimatedNrItems\" : 10, \n        \"inVariable\" : { \n          \"id\" : 2, \n          \"name\" : \"1\" \n        }, \n        \"outVariable\" : { \n          \"id\" : 0, \n          \"name\" : \"i\" \n        } \n      }, \n      { \n        \"type\" : \"ReturnNode\", \n        \"dependencies\" : [ \n          3 \n        ], \n        \"id\" : 5, \n        \"estimatedCost\" : 23, \n        \"estimatedNrItems\" : 10, \n        \"inVariable\" : { \n          \"id\" : 4, \n          \"name\" : \"3\" \n        } \n      } \n    ], \n    \"rules\" : [ \n      \"move-calculations-up\", \n      \"move-calculations-up-2\" \n    ], \n    \"collections\" : [ ], \n    \"variables\" : [ \n      { \n        \"id\" : 4, \n        \"name\" : \"3\" \n      }, \n      { \n        \"id\" : 2, \n        \"name\" : \"1\" \n      }, \n      { \n        \"id\" : 0, \n        \"name\" : \"i\" \n      } \n    ], \n    \"estimatedCost\" : 23, \n    \"estimatedNrItems\" : 10 \n  }, \n  \"warnings\" : [ \n    { \n      \"code\" : 1562, \n      \"message\" : \"division by zero\" \n    } \n  ], \n  \"stats\" : { \n    \"rulesExecuted\" : 26, \n    \"rulesSkipped\" : 0, \n    \"plansCreated\" : 1 \n  }, \n  \"cacheable\" : false, \n  \"error\" : false, \n  \"code\" : 200 \n}\n
\n\n\n\n\n#Example:\n Invalid query (missing bind parameter)\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \n  \"query\" : \"FOR p IN products FILTER p.id == @id LIMIT 2 RETURN p.n\" \n}\nEOF\n\nHTTP/1.1 400 Bad Request\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"error\" : true, \n  \"code\" : 400, \n  \"errorNum\" : 1551, \n  \"errorMessage\" : \"no value specified for declared bind parameter 'id' (while parsing)\" \n}\n
\n\n\n\n\n#Example:\n The data returned in the **plan** attribute of the result contains one element per AQL top-level statement\n(i.e. `FOR`, `RETURN`, `FILTER` etc.). If the query optimizer removed some unnecessary statements,\nthe result might also contain less elements than there were top-level statements in the AQL query.\n\nThe following example shows a query with a non-sensible filter condition that\nthe optimizer has removed so that there are less top-level statements.\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \"query\" : \"FOR i IN [ 1, 2, 3 ] FILTER 1 == 2 RETURN i\" }\nEOF\n\nHTTP/1.1 200 OK\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"plan\" : { \n    \"nodes\" : [ \n      { \n        \"type\" : \"SingletonNode\", \n        \"dependencies\" : [ ], \n        \"id\" : 1, \n        \"estimatedCost\" : 1, \n        \"estimatedNrItems\" : 1 \n      }, \n      { \n        \"type\" : \"CalculationNode\", \n        \"dependencies\" : [ \n          1 \n        ], \n        \"id\" : 2, \n        \"estimatedCost\" : 2, \n        \"estimatedNrItems\" : 1, \n        \"expression\" : { \n          \"type\" : \"array\", \n          \"subNodes\" : [ \n            { \n              \"type\" : \"value\", \n              \"value\" : 1 \n            }, \n            { \n              \"type\" : \"value\", \n              \"value\" : 2 \n            }, \n            { \n              \"type\" : \"value\", \n              \"value\" : 3 \n            } \n          ] \n        }, \n        \"outVariable\" : { \n          \"id\" : 2, \n          \"name\" : \"1\" \n        }, \n        \"canThrow\" : false, \n        \"expressionType\" : \"json\" \n      }, \n      { \n        \"type\" : \"NoResultsNode\", \n        \"dependencies\" : [ \n          2 \n        ], \n        \"id\" : 7, \n        \"estimatedCost\" : 0.5, \n        \"estimatedNrItems\" : 0 \n      }, \n      { \n        \"type\" : \"EnumerateListNode\", \n        \"dependencies\" : [ \n          7 \n        ], \n        \"id\" : 3, \n        \"estimatedCost\" : 0.5, \n        \"estimatedNrItems\" : 0, \n        \"inVariable\" : { \n          \"id\" : 2, \n          \"name\" : \"1\" \n        }, \n        \"outVariable\" : { \n          \"id\" : 0, \n          \"name\" : \"i\" \n        } \n      }, \n      { \n        \"type\" : \"ReturnNode\", \n        \"dependencies\" : [ \n          3 \n        ], \n        \"id\" : 6, \n        \"estimatedCost\" : 0.5, \n        \"estimatedNrItems\" : 0, \n        \"inVariable\" : { \n          \"id\" : 0, \n          \"name\" : \"i\" \n        } \n      } \n    ], \n    \"rules\" : [ \n      \"move-calculations-up\", \n      \"move-filters-up\", \n      \"remove-unnecessary-filters\", \n      \"remove-unnecessary-calculations\" \n    ], \n    \"collections\" : [ ], \n    \"variables\" : [ \n      { \n        \"id\" : 4, \n        \"name\" : \"3\" \n      }, \n      { \n        \"id\" : 2, \n        \"name\" : \"1\" \n      }, \n      { \n        \"id\" : 0, \n        \"name\" : \"i\" \n      } \n    ], \n    \"estimatedCost\" : 0.5, \n    \"estimatedNrItems\" : 0 \n  }, \n  \"warnings\" : [ ], \n  \"stats\" : { \n    \"rulesExecuted\" : 26, \n    \"rulesSkipped\" : 0, \n    \"plansCreated\" : 1 \n  }, \n  \"cacheable\" : true, \n  \"error\" : false, \n  \"code\" : 200 \n}\n
\n\n\n\n\n", + "description": "**A json post document with these Properties is required:**\n\n - **query**: the query which you want explained; If the query references any bind variables,\n these must also be passed in the attribute *bindVars*. Additional\n options for the query can be passed in the *options* attribute.\n - **options**:\n - **optimizer.rules**: an array of to-be-included or to-be-excluded optimizer rules\n can be put into this attribute, telling the optimizer to include or exclude\n specific rules. To disable a rule, prefix its name with a `-`, to enable a rule, prefix it\n with a `+`. There is also a pseudo-rule `all`, which will match all optimizer rules. of type string\n - **maxNumberOfPlans**: an optional maximum number of plans that the optimizer is \n allowed to generate. Setting this attribute to a low value allows to put a\n cap on the amount of work the optimizer does.\n - **allPlans**: if set to *true*, all possible execution plans will be returned.\n The default is *false*, meaning only the optimal plan will be returned.\n - **bindVars**: key/value pairs representing the bind values of type object\n\n\n\n\n\nTo explain how an AQL query would be executed on the server, the query string\ncan be sent to the server via an HTTP POST request. The server will then validate\nthe query and create an execution plan for it. The execution plan will be\nreturned, but the query will not be executed.\n\nThe execution plan that is returned by the server can be used to estimate the\nprobable performance of the query. Though the actual performance will depend\non many different factors, the execution plan normally can provide some rough\nestimates on the amount of work the server needs to do in order to actually run \nthe query.\n\nBy default, the explain operation will return the optimal plan as chosen by\nthe query optimizer The optimal plan is the plan with the lowest total estimated\ncost. The plan will be returned in the attribute *plan* of the response object.\nIf the option *allPlans* is specified in the request, the result will contain \nall plans created by the optimizer. The plans will then be returned in the \nattribute *plans*.\n\nThe result will also contain an attribute *warnings*, which is an array of \nwarnings that occurred during optimization or execution plan creation. Additionally,\na *stats* attribute is contained in the result with some optimizer statistics.\nIf *allPlans* is set to *false*, the result will contain an attribute *cacheable* \nthat states whether the query results can be cached on the server if the query\nresult cache were used. The *cacheable* attribute is not present when *allPlans*\nis set to *true*.\n\nEach plan in the result is a JSON object with the following attributes:\n- *nodes*: the array of execution nodes of the plan. The array of available node types\n can be found [here](../../AQL/ExecutionAndPerformance/Optimizer.html)\n\n- *estimatedCost*: the total estimated cost for the plan. If there are multiple\n plans, the optimizer will choose the plan with the lowest total cost.\n\n- *collections*: an array of collections used in the query\n\n- *rules*: an array of rules the optimizer applied. An overview of the\n available rules can be found [here](../../AQL/ExecutionAndPerformance/Optimizer.html)\n\n- *variables*: array of variables used in the query (note: this may contain\n internal variables created by the optimizer)\n\n\n\n\n#Example:\n Valid query\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \n  \"query\" : \"FOR p IN products RETURN p\" \n}\nEOF\n\nHTTP/1.1 200 OK\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"plan\" : { \n    \"nodes\" : [ \n      { \n        \"type\" : \"SingletonNode\", \n        \"dependencies\" : [ ], \n        \"id\" : 1, \n        \"estimatedCost\" : 1, \n        \"estimatedNrItems\" : 1 \n      }, \n      { \n        \"type\" : \"EnumerateCollectionNode\", \n        \"dependencies\" : [ \n          1 \n        ], \n        \"id\" : 2, \n        \"estimatedCost\" : 11, \n        \"estimatedNrItems\" : 10, \n        \"database\" : \"_system\", \n        \"collection\" : \"products\", \n        \"outVariable\" : { \n          \"id\" : 0, \n          \"name\" : \"p\" \n        }, \n        \"random\" : false \n      }, \n      { \n        \"type\" : \"ReturnNode\", \n        \"dependencies\" : [ \n          2 \n        ], \n        \"id\" : 3, \n        \"estimatedCost\" : 21, \n        \"estimatedNrItems\" : 10, \n        \"inVariable\" : { \n          \"id\" : 0, \n          \"name\" : \"p\" \n        } \n      } \n    ], \n    \"rules\" : [ ], \n    \"collections\" : [ \n      { \n        \"name\" : \"products\", \n        \"type\" : \"read\" \n      } \n    ], \n    \"variables\" : [ \n      { \n        \"id\" : 0, \n        \"name\" : \"p\" \n      } \n    ], \n    \"estimatedCost\" : 21, \n    \"estimatedNrItems\" : 10 \n  }, \n  \"warnings\" : [ ], \n  \"stats\" : { \n    \"rulesExecuted\" : 26, \n    \"rulesSkipped\" : 0, \n    \"plansCreated\" : 1 \n  }, \n  \"cacheable\" : true, \n  \"error\" : false, \n  \"code\" : 200 \n}\n
\n\n\n\n\n#Example:\n A plan with some optimizer rules applied\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \n  \"query\" : \"FOR p IN products LET a = p.id FILTER a == 4 LET name = p.name SORT p.id LIMIT 1 RETURN name\" \n}\nEOF\n\nHTTP/1.1 200 OK\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"plan\" : { \n    \"nodes\" : [ \n      { \n        \"type\" : \"SingletonNode\", \n        \"dependencies\" : [ ], \n        \"id\" : 1, \n        \"estimatedCost\" : 1, \n        \"estimatedNrItems\" : 1 \n      }, \n      { \n        \"type\" : \"IndexNode\", \n        \"dependencies\" : [ \n          1 \n        ], \n        \"id\" : 11, \n        \"estimatedCost\" : 11, \n        \"estimatedNrItems\" : 10, \n        \"database\" : \"_system\", \n        \"collection\" : \"products\", \n        \"outVariable\" : { \n          \"id\" : 0, \n          \"name\" : \"p\" \n        }, \n        \"indexes\" : [ \n          { \n            \"id\" : \"10551\", \n            \"type\" : \"skiplist\", \n            \"fields\" : [ \n              \"id\" \n            ], \n            \"unique\" : false, \n            \"sparse\" : false \n          } \n        ], \n        \"condition\" : { \n        }, \n        \"reverse\" : false \n      }, \n      { \n        \"type\" : \"CalculationNode\", \n        \"dependencies\" : [ \n          11 \n        ], \n        \"id\" : 4, \n        \"estimatedCost\" : 21, \n        \"estimatedNrItems\" : 10, \n        \"expression\" : { \n          \"type\" : \"compare ==\", \n          \"subNodes\" : [ \n            { \n              \"type\" : \"attribute access\", \n              \"name\" : \"id\", \n              \"subNodes\" : [ \n                { \n                  \"type\" : \"reference\", \n                  \"name\" : \"p\", \n                  \"id\" : 0 \n                } \n              ] \n            }, \n            { \n              \"type\" : \"value\", \n              \"value\" : 4 \n            } \n          ] \n        }, \n        \"outVariable\" : { \n          \"id\" : 4, \n          \"name\" : \"3\" \n        }, \n        \"canThrow\" : false, \n        \"expressionType\" : \"simple\" \n      }, \n      { \n        \"type\" : \"FilterNode\", \n        \"dependencies\" : [ \n          4 \n        ], \n        \"id\" : 5, \n        \"estimatedCost\" : 31, \n        \"estimatedNrItems\" : 10, \n        \"inVariable\" : { \n          \"id\" : 4, \n          \"name\" : \"3\" \n        } \n      }, \n      { \n        \"type\" : \"LimitNode\", \n        \"dependencies\" : [ \n          5 \n        ], \n        \"id\" : 9, \n        \"estimatedCost\" : 32, \n        \"estimatedNrItems\" : 1, \n        \"offset\" : 0, \n        \"limit\" : 1, \n        \"fullCount\" : false \n      }, \n      { \n        \"type\" : \"CalculationNode\", \n        \"dependencies\" : [ \n          9 \n        ], \n        \"id\" : 6, \n        \"estimatedCost\" : 33, \n        \"estimatedNrItems\" : 1, \n        \"expression\" : { \n          \"type\" : \"attribute access\", \n          \"name\" : \"name\", \n          \"subNodes\" : [ \n            { \n              \"type\" : \"reference\", \n              \"name\" : \"p\", \n              \"id\" : 0 \n            } \n          ] \n        }, \n        \"outVariable\" : { \n          \"id\" : 2, \n          \"name\" : \"name\" \n        }, \n        \"canThrow\" : false, \n        \"expressionType\" : \"attribute\" \n      }, \n      { \n        \"type\" : \"ReturnNode\", \n        \"dependencies\" : [ \n          6 \n        ], \n        \"id\" : 10, \n        \"estimatedCost\" : 34, \n        \"estimatedNrItems\" : 1, \n        \"inVariable\" : { \n          \"id\" : 2, \n          \"name\" : \"name\" \n        } \n      } \n    ], \n    \"rules\" : [ \n      \"move-calculations-up\", \n      \"remove-redundant-calculations\", \n      \"remove-unnecessary-calculations\", \n      \"move-calculations-up-2\", \n      \"use-index-for-sort\", \n      \"remove-unnecessary-calculations-2\", \n      \"move-calculations-down\" \n    ], \n    \"collections\" : [ \n      { \n        \"name\" : \"products\", \n        \"type\" : \"read\" \n      } \n    ], \n    \"variables\" : [ \n      { \n        \"id\" : 6, \n        \"name\" : \"5\" \n      }, \n      { \n        \"id\" : 4, \n        \"name\" : \"3\" \n      }, \n      { \n        \"id\" : 2, \n        \"name\" : \"name\" \n      }, \n      { \n        \"id\" : 1, \n        \"name\" : \"a\" \n      }, \n      { \n        \"id\" : 0, \n        \"name\" : \"p\" \n      } \n    ], \n    \"estimatedCost\" : 34, \n    \"estimatedNrItems\" : 1 \n  }, \n  \"warnings\" : [ ], \n  \"stats\" : { \n    \"rulesExecuted\" : 26, \n    \"rulesSkipped\" : 0, \n    \"plansCreated\" : 1 \n  }, \n  \"cacheable\" : true, \n  \"error\" : false, \n  \"code\" : 200 \n}\n
\n\n\n\n\n#Example:\n Using some options\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \n  \"query\" : \"FOR p IN products LET a = p.id FILTER a == 4 LET name = p.name SORT p.id LIMIT 1 RETURN name\", \n  \"options\" : { \n    \"maxNumberOfPlans\" : 2, \n    \"allPlans\" : true, \n    \"optimizer\" : { \n      \"rules\" : [ \n        \"-all\", \n        \"+use-index-for-sort\", \n        \"+use-index-range\" \n      ] \n    } \n  } \n}\nEOF\n\nHTTP/1.1 200 OK\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"plans\" : [ \n    { \n      \"nodes\" : [ \n        { \n          \"type\" : \"SingletonNode\", \n          \"dependencies\" : [ ], \n          \"id\" : 1, \n          \"estimatedCost\" : 1, \n          \"estimatedNrItems\" : 1 \n        }, \n        { \n          \"type\" : \"IndexNode\", \n          \"dependencies\" : [ \n            1 \n          ], \n          \"id\" : 11, \n          \"estimatedCost\" : 11, \n          \"estimatedNrItems\" : 10, \n          \"database\" : \"_system\", \n          \"collection\" : \"products\", \n          \"outVariable\" : { \n            \"id\" : 0, \n            \"name\" : \"p\" \n          }, \n          \"indexes\" : [ \n            { \n              \"id\" : \"10589\", \n              \"type\" : \"skiplist\", \n              \"fields\" : [ \n                \"id\" \n              ], \n              \"unique\" : false, \n              \"sparse\" : false \n            } \n          ], \n          \"condition\" : { \n          }, \n          \"reverse\" : false \n        }, \n        { \n          \"type\" : \"CalculationNode\", \n          \"dependencies\" : [ \n            11 \n          ], \n          \"id\" : 3, \n          \"estimatedCost\" : 21, \n          \"estimatedNrItems\" : 10, \n          \"expression\" : { \n            \"type\" : \"attribute access\", \n            \"name\" : \"id\", \n            \"subNodes\" : [ \n              { \n                \"type\" : \"reference\", \n                \"name\" : \"p\", \n                \"id\" : 0 \n              } \n            ] \n          }, \n          \"outVariable\" : { \n            \"id\" : 1, \n            \"name\" : \"a\" \n          }, \n          \"canThrow\" : false, \n          \"expressionType\" : \"attribute\" \n        }, \n        { \n          \"type\" : \"CalculationNode\", \n          \"dependencies\" : [ \n            3 \n          ], \n          \"id\" : 4, \n          \"estimatedCost\" : 31, \n          \"estimatedNrItems\" : 10, \n          \"expression\" : { \n            \"type\" : \"compare ==\", \n            \"subNodes\" : [ \n              { \n                \"type\" : \"reference\", \n                \"name\" : \"a\", \n                \"id\" : 1 \n              }, \n              { \n                \"type\" : \"value\", \n                \"value\" : 4 \n              } \n            ] \n          }, \n          \"outVariable\" : { \n            \"id\" : 4, \n            \"name\" : \"3\" \n          }, \n          \"canThrow\" : false, \n          \"expressionType\" : \"simple\" \n        }, \n        { \n          \"type\" : \"FilterNode\", \n          \"dependencies\" : [ \n            4 \n          ], \n          \"id\" : 5, \n          \"estimatedCost\" : 41, \n          \"estimatedNrItems\" : 10, \n          \"inVariable\" : { \n            \"id\" : 4, \n            \"name\" : \"3\" \n          } \n        }, \n        { \n          \"type\" : \"CalculationNode\", \n          \"dependencies\" : [ \n            5 \n          ], \n          \"id\" : 6, \n          \"estimatedCost\" : 51, \n          \"estimatedNrItems\" : 10, \n          \"expression\" : { \n            \"type\" : \"attribute access\", \n            \"name\" : \"name\", \n            \"subNodes\" : [ \n              { \n                \"type\" : \"reference\", \n                \"name\" : \"p\", \n                \"id\" : 0 \n              } \n            ] \n          }, \n          \"outVariable\" : { \n            \"id\" : 2, \n            \"name\" : \"name\" \n          }, \n          \"canThrow\" : false, \n          \"expressionType\" : \"attribute\" \n        }, \n        { \n          \"type\" : \"CalculationNode\", \n          \"dependencies\" : [ \n            6 \n          ], \n          \"id\" : 7, \n          \"estimatedCost\" : 61, \n          \"estimatedNrItems\" : 10, \n          \"expression\" : { \n            \"type\" : \"attribute access\", \n            \"name\" : \"id\", \n            \"subNodes\" : [ \n              { \n                \"type\" : \"reference\", \n                \"name\" : \"p\", \n                \"id\" : 0 \n              } \n            ] \n          }, \n          \"outVariable\" : { \n            \"id\" : 6, \n            \"name\" : \"5\" \n          }, \n          \"canThrow\" : false, \n          \"expressionType\" : \"attribute\" \n        }, \n        { \n          \"type\" : \"LimitNode\", \n          \"dependencies\" : [ \n            7 \n          ], \n          \"id\" : 9, \n          \"estimatedCost\" : 62, \n          \"estimatedNrItems\" : 1, \n          \"offset\" : 0, \n          \"limit\" : 1, \n          \"fullCount\" : false \n        }, \n        { \n          \"type\" : \"ReturnNode\", \n          \"dependencies\" : [ \n            9 \n          ], \n          \"id\" : 10, \n          \"estimatedCost\" : 63, \n          \"estimatedNrItems\" : 1, \n          \"inVariable\" : { \n            \"id\" : 2, \n            \"name\" : \"name\" \n          } \n        } \n      ], \n      \"rules\" : [ \n        \"use-index-for-sort\" \n      ], \n      \"collections\" : [ \n        { \n          \"name\" : \"products\", \n          \"type\" : \"read\" \n        } \n      ], \n      \"variables\" : [ \n        { \n          \"id\" : 6, \n          \"name\" : \"5\" \n        }, \n        { \n          \"id\" : 4, \n          \"name\" : \"3\" \n        }, \n        { \n          \"id\" : 2, \n          \"name\" : \"name\" \n        }, \n        { \n          \"id\" : 1, \n          \"name\" : \"a\" \n        }, \n        { \n          \"id\" : 0, \n          \"name\" : \"p\" \n        } \n      ], \n      \"estimatedCost\" : 63, \n      \"estimatedNrItems\" : 1 \n    } \n  ], \n  \"warnings\" : [ ], \n  \"stats\" : { \n    \"rulesExecuted\" : 1, \n    \"rulesSkipped\" : 25, \n    \"plansCreated\" : 1 \n  }, \n  \"error\" : false, \n  \"code\" : 200 \n}\n
\n\n\n\n\n#Example:\n Returning all plans\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \n  \"query\" : \"FOR p IN products FILTER p.id == 25 RETURN p\", \n  \"options\" : { \n    \"allPlans\" : true \n  } \n}\nEOF\n\nHTTP/1.1 200 OK\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"plans\" : [ \n    { \n      \"nodes\" : [ \n        { \n          \"type\" : \"SingletonNode\", \n          \"dependencies\" : [ ], \n          \"id\" : 1, \n          \"estimatedCost\" : 1, \n          \"estimatedNrItems\" : 1 \n        }, \n        { \n          \"type\" : \"IndexNode\", \n          \"dependencies\" : [ \n            1 \n          ], \n          \"id\" : 6, \n          \"estimatedCost\" : 1.99, \n          \"estimatedNrItems\" : 1, \n          \"database\" : \"_system\", \n          \"collection\" : \"products\", \n          \"outVariable\" : { \n            \"id\" : 0, \n            \"name\" : \"p\" \n          }, \n          \"indexes\" : [ \n            { \n              \"id\" : \"10537\", \n              \"type\" : \"hash\", \n              \"fields\" : [ \n                \"id\" \n              ], \n              \"selectivityEstimate\" : 1, \n              \"unique\" : false, \n              \"sparse\" : false \n            } \n          ], \n          \"condition\" : { \n            \"type\" : \"n-ary or\", \n            \"subNodes\" : [ \n              { \n                \"type\" : \"n-ary and\", \n                \"subNodes\" : [ \n                  { \n                    \"type\" : \"compare ==\", \n                    \"subNodes\" : [ \n                      { \n                        \"type\" : \"attribute access\", \n                        \"name\" : \"id\", \n                        \"subNodes\" : [ \n                          { \n                            \"type\" : \"reference\", \n                            \"name\" : \"p\", \n                            \"id\" : 0 \n                          } \n                        ] \n                      }, \n                      { \n                        \"type\" : \"value\", \n                        \"value\" : 25 \n                      } \n                    ] \n                  } \n                ] \n              } \n            ] \n          }, \n          \"reverse\" : false \n        }, \n        { \n          \"type\" : \"ReturnNode\", \n          \"dependencies\" : [ \n            6 \n          ], \n          \"id\" : 5, \n          \"estimatedCost\" : 2.99, \n          \"estimatedNrItems\" : 1, \n          \"inVariable\" : { \n            \"id\" : 0, \n            \"name\" : \"p\" \n          } \n        } \n      ], \n      \"rules\" : [ \n        \"use-indexes\", \n        \"remove-filter-covered-by-index\" \n      ], \n      \"collections\" : [ \n        { \n          \"name\" : \"products\", \n          \"type\" : \"read\" \n        } \n      ], \n      \"variables\" : [ \n        { \n          \"id\" : 2, \n          \"name\" : \"1\" \n        }, \n        { \n          \"id\" : 0, \n          \"name\" : \"p\" \n        } \n      ], \n      \"estimatedCost\" : 2.99, \n      \"estimatedNrItems\" : 1 \n    } \n  ], \n  \"warnings\" : [ ], \n  \"stats\" : { \n    \"rulesExecuted\" : 26, \n    \"rulesSkipped\" : 0, \n    \"plansCreated\" : 1 \n  }, \n  \"error\" : false, \n  \"code\" : 200 \n}\n
\n\n\n\n\n#Example:\n A query that produces a warning\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \n  \"query\" : \"FOR i IN 1..10 RETURN 1 / 0\" \n}\nEOF\n\nHTTP/1.1 200 OK\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"plan\" : { \n    \"nodes\" : [ \n      { \n        \"type\" : \"SingletonNode\", \n        \"dependencies\" : [ ], \n        \"id\" : 1, \n        \"estimatedCost\" : 1, \n        \"estimatedNrItems\" : 1 \n      }, \n      { \n        \"type\" : \"CalculationNode\", \n        \"dependencies\" : [ \n          1 \n        ], \n        \"id\" : 2, \n        \"estimatedCost\" : 2, \n        \"estimatedNrItems\" : 1, \n        \"expression\" : { \n          \"type\" : \"range\", \n          \"subNodes\" : [ \n            { \n              \"type\" : \"value\", \n              \"value\" : 1 \n            }, \n            { \n              \"type\" : \"value\", \n              \"value\" : 10 \n            } \n          ] \n        }, \n        \"outVariable\" : { \n          \"id\" : 2, \n          \"name\" : \"1\" \n        }, \n        \"canThrow\" : false, \n        \"expressionType\" : \"simple\" \n      }, \n      { \n        \"type\" : \"CalculationNode\", \n        \"dependencies\" : [ \n          2 \n        ], \n        \"id\" : 4, \n        \"estimatedCost\" : 3, \n        \"estimatedNrItems\" : 1, \n        \"expression\" : { \n          \"type\" : \"value\", \n          \"value\" : null \n        }, \n        \"outVariable\" : { \n          \"id\" : 4, \n          \"name\" : \"3\" \n        }, \n        \"canThrow\" : false, \n        \"expressionType\" : \"json\" \n      }, \n      { \n        \"type\" : \"EnumerateListNode\", \n        \"dependencies\" : [ \n          4 \n        ], \n        \"id\" : 3, \n        \"estimatedCost\" : 13, \n        \"estimatedNrItems\" : 10, \n        \"inVariable\" : { \n          \"id\" : 2, \n          \"name\" : \"1\" \n        }, \n        \"outVariable\" : { \n          \"id\" : 0, \n          \"name\" : \"i\" \n        } \n      }, \n      { \n        \"type\" : \"ReturnNode\", \n        \"dependencies\" : [ \n          3 \n        ], \n        \"id\" : 5, \n        \"estimatedCost\" : 23, \n        \"estimatedNrItems\" : 10, \n        \"inVariable\" : { \n          \"id\" : 4, \n          \"name\" : \"3\" \n        } \n      } \n    ], \n    \"rules\" : [ \n      \"move-calculations-up\", \n      \"move-calculations-up-2\" \n    ], \n    \"collections\" : [ ], \n    \"variables\" : [ \n      { \n        \"id\" : 4, \n        \"name\" : \"3\" \n      }, \n      { \n        \"id\" : 2, \n        \"name\" : \"1\" \n      }, \n      { \n        \"id\" : 0, \n        \"name\" : \"i\" \n      } \n    ], \n    \"estimatedCost\" : 23, \n    \"estimatedNrItems\" : 10 \n  }, \n  \"warnings\" : [ \n    { \n      \"code\" : 1562, \n      \"message\" : \"division by zero\" \n    } \n  ], \n  \"stats\" : { \n    \"rulesExecuted\" : 26, \n    \"rulesSkipped\" : 0, \n    \"plansCreated\" : 1 \n  }, \n  \"cacheable\" : false, \n  \"error\" : false, \n  \"code\" : 200 \n}\n
\n\n\n\n\n#Example:\n Invalid query (missing bind parameter)\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \n  \"query\" : \"FOR p IN products FILTER p.id == @id LIMIT 2 RETURN p.n\" \n}\nEOF\n\nHTTP/1.1 400 Bad Request\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"error\" : true, \n  \"code\" : 400, \n  \"errorNum\" : 1551, \n  \"errorMessage\" : \"no value specified for declared bind parameter 'id' (while parsing)\" \n}\n
\n\n\n\n\n#Example:\n The data returned in the **plan** attribute of the result contains one element per AQL top-level statement\n(i.e. `FOR`, `RETURN`, `FILTER` etc.). If the query optimizer removed some unnecessary statements,\nthe result might also contain less elements than there were top-level statements in the AQL query.\n\nThe following example shows a query with a non-sensible filter condition that\nthe optimizer has removed so that there are less top-level statements.\n\n
shell> curl -X POST --data-binary @- --dump - http://localhost:8529/_api/explain <<EOF\n{ \"query\" : \"FOR i IN [ 1, 2, 3 ] FILTER 1 == 2 RETURN i\" }\nEOF\n\nHTTP/1.1 200 OK\ncontent-type: application/json; charset=utf-8\n\n{ \n  \"plan\" : { \n    \"nodes\" : [ \n      { \n        \"type\" : \"SingletonNode\", \n        \"dependencies\" : [ ], \n        \"id\" : 1, \n        \"estimatedCost\" : 1, \n        \"estimatedNrItems\" : 1 \n      }, \n      { \n        \"type\" : \"CalculationNode\", \n        \"dependencies\" : [ \n          1 \n        ], \n        \"id\" : 2, \n        \"estimatedCost\" : 2, \n        \"estimatedNrItems\" : 1, \n        \"expression\" : { \n          \"type\" : \"array\", \n          \"subNodes\" : [ \n            { \n              \"type\" : \"value\", \n              \"value\" : 1 \n            }, \n            { \n              \"type\" : \"value\", \n              \"value\" : 2 \n            }, \n            { \n              \"type\" : \"value\", \n              \"value\" : 3 \n            } \n          ] \n        }, \n        \"outVariable\" : { \n          \"id\" : 2, \n          \"name\" : \"1\" \n        }, \n        \"canThrow\" : false, \n        \"expressionType\" : \"json\" \n      }, \n      { \n        \"type\" : \"NoResultsNode\", \n        \"dependencies\" : [ \n          2 \n        ], \n        \"id\" : 7, \n        \"estimatedCost\" : 0.5, \n        \"estimatedNrItems\" : 0 \n      }, \n      { \n        \"type\" : \"EnumerateListNode\", \n        \"dependencies\" : [ \n          7 \n        ], \n        \"id\" : 3, \n        \"estimatedCost\" : 0.5, \n        \"estimatedNrItems\" : 0, \n        \"inVariable\" : { \n          \"id\" : 2, \n          \"name\" : \"1\" \n        }, \n        \"outVariable\" : { \n          \"id\" : 0, \n          \"name\" : \"i\" \n        } \n      }, \n      { \n        \"type\" : \"ReturnNode\", \n        \"dependencies\" : [ \n          3 \n        ], \n        \"id\" : 6, \n        \"estimatedCost\" : 0.5, \n        \"estimatedNrItems\" : 0, \n        \"inVariable\" : { \n          \"id\" : 0, \n          \"name\" : \"i\" \n        } \n      } \n    ], \n    \"rules\" : [ \n      \"move-calculations-up\", \n      \"move-filters-up\", \n      \"remove-unnecessary-filters\", \n      \"remove-unnecessary-calculations\" \n    ], \n    \"collections\" : [ ], \n    \"variables\" : [ \n      { \n        \"id\" : 4, \n        \"name\" : \"3\" \n      }, \n      { \n        \"id\" : 2, \n        \"name\" : \"1\" \n      }, \n      { \n        \"id\" : 0, \n        \"name\" : \"i\" \n      } \n    ], \n    \"estimatedCost\" : 0.5, \n    \"estimatedNrItems\" : 0 \n  }, \n  \"warnings\" : [ ], \n  \"stats\" : { \n    \"rulesExecuted\" : 26, \n    \"rulesSkipped\" : 0, \n    \"plansCreated\" : 1 \n  }, \n  \"cacheable\" : true, \n  \"error\" : false, \n  \"code\" : 200 \n}\n
\n\n\n\n\n", "parameters": [ { "in": "body", From 0f5b4624eafd7694460c4fd5c7ee213e06082124 Mon Sep 17 00:00:00 2001 From: Alan Plum Date: Tue, 14 Jun 2016 17:17:50 +0200 Subject: [PATCH 05/10] Unbreak the build --- js/server/modules/@arangodb/foxx/router/response.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/server/modules/@arangodb/foxx/router/response.js b/js/server/modules/@arangodb/foxx/router/response.js index 2881748ac6..d0a5ad0506 100644 --- a/js/server/modules/@arangodb/foxx/router/response.js +++ b/js/server/modules/@arangodb/foxx/router/response.js @@ -54,6 +54,10 @@ module.exports = class SyntheticResponse { return this._raw.headers; } + set headers(headers) { + this._raw.headers = headers; + } + get statusCode() { return this._raw.responseCode; } From a8219b4818b6ff4de943fdb00a20ab9a35edcb8a Mon Sep 17 00:00:00 2001 From: Alan Plum Date: Tue, 14 Jun 2016 17:20:06 +0200 Subject: [PATCH 06/10] Unbreak the build I say --- js/server/modules/@arangodb/foxx/router/request.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/server/modules/@arangodb/foxx/router/request.js b/js/server/modules/@arangodb/foxx/router/request.js index bb4b323dda..a039815fdc 100644 --- a/js/server/modules/@arangodb/foxx/router/request.js +++ b/js/server/modules/@arangodb/foxx/router/request.js @@ -64,6 +64,10 @@ module.exports = class SyntheticRequest { return this._raw.headers; } + set headers(headers) { + this._raw.headers = headers; + } + get method() { return this._raw.requestType; } From f014cf964b941d2b2a4b333789fe6dcaa814b15b Mon Sep 17 00:00:00 2001 From: hkernbach Date: Tue, 14 Jun 2016 17:22:01 +0200 Subject: [PATCH 07/10] fixed modal display bug [ci skip] --- .../frontend/js/templates/modalGraphTable.ejs | 4 ++-- .../aardvark/APP/frontend/scss/_graphViewer.scss | 16 ++++++++++++++++ .../aardvark/APP/frontend/scss/_modals.scss | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/templates/modalGraphTable.ejs b/js/apps/system/_admin/aardvark/APP/frontend/js/templates/modalGraphTable.ejs index 846feb8ca2..ea5fa45f15 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/templates/modalGraphTable.ejs +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/templates/modalGraphTable.ejs @@ -93,10 +93,10 @@ %> <% if (row.addAdd) {%> - + <% } %> <% if (row.addDelete) {%> - + <% } %> <% break; diff --git a/js/apps/system/_admin/aardvark/APP/frontend/scss/_graphViewer.scss b/js/apps/system/_admin/aardvark/APP/frontend/scss/_graphViewer.scss index f5e92b1081..8db939c4c7 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/scss/_graphViewer.scss +++ b/js/apps/system/_admin/aardvark/APP/frontend/scss/_graphViewer.scss @@ -146,4 +146,20 @@ div.gv-colour-list { } } +#tab-content-create-graph { + .addAfter, + .addDelete, + .delete { + margin-top: -9px; + position: absolute; + right: 13px; + } + .tableRow { + &.first { + border-top: 10px solid $c-white; + } + } + + +} diff --git a/js/apps/system/_admin/aardvark/APP/frontend/scss/_modals.scss b/js/apps/system/_admin/aardvark/APP/frontend/scss/_modals.scss index a269c3ded7..2e7d694acf 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/scss/_modals.scss +++ b/js/apps/system/_admin/aardvark/APP/frontend/scss/_modals.scss @@ -151,7 +151,7 @@ tr { &.spacer { - height: 10px; + height: 20px; } &.first { From 5c8640135533ca6739e60a2f679c0a2919d04e66 Mon Sep 17 00:00:00 2001 From: hkernbach Date: Tue, 14 Jun 2016 17:22:19 +0200 Subject: [PATCH 08/10] fixed documentation link [ci skip] --- .../_admin/aardvark/APP/frontend/js/templates/supportView.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/templates/supportView.ejs b/js/apps/system/_admin/aardvark/APP/frontend/js/templates/supportView.ejs index d9a54869ef..88d2cb652a 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/templates/supportView.ejs +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/templates/supportView.ejs @@ -93,7 +93,7 @@
  • Foxx Anatomy
  • Writing Your First Microservice
  • Legacy mode for 2.8 services
  • -
  • Go to Foxx startpage
  • +
  • Go to Foxx startpage
  • From 3b6860604f35356b68c61624ee6960dead84a84c Mon Sep 17 00:00:00 2001 From: Alan Plum Date: Tue, 14 Jun 2016 17:23:19 +0200 Subject: [PATCH 09/10] Unbreak the docs --- Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp b/Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp index 666cdfa7e1..d3135e1b74 100644 --- a/Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp +++ b/Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp @@ -92,6 +92,8 @@ Returns the endpoint. **Examples** ```js +router.get(/* ... */) +.queryParam('num', joi.number().required()); ``` !SECTION body From b5667ca744de3a1857e3baa1b11e31539d3c3cc0 Mon Sep 17 00:00:00 2001 From: Alan Plum Date: Tue, 14 Jun 2016 17:23:30 +0200 Subject: [PATCH 10/10] Consistent docs links --- Documentation/Books/Manual/Foxx/Assets.mdpp | 1 - .../Foxx/{Anatomy.mdpp => AtAGlance.mdpp} | 2 +- .../Books/Manual/Foxx/Dependencies.mdpp | 2 + .../Books/Manual/Foxx/GettingStarted.mdpp | 45 ++++++------------- .../Books/Manual/Foxx/LegacyMode.mdpp | 4 +- Documentation/Books/Manual/Foxx/Manifest.mdpp | 24 ++++------ .../Books/Manual/Foxx/Router/Endpoints.mdpp | 6 +-- .../Books/Manual/Foxx/Router/README.mdpp | 12 ++--- .../Books/Manual/Foxx/Router/Request.mdpp | 13 ++---- .../Books/Manual/Foxx/Sessions/README.mdpp | 13 ++---- .../Foxx/Sessions/Storages/Collection.mdpp | 4 +- .../Manual/Foxx/Sessions/Storages/JWT.mdpp | 4 +- .../Foxx/Sessions/Transports/Cookie.mdpp | 7 +-- .../Foxx/Sessions/Transports/Header.mdpp | 4 +- .../Foxx/Sessions/Transports/README.mdpp | 7 +-- Documentation/Books/Manual/Foxx/Users.mdpp | 7 +-- Documentation/Books/Manual/SUMMARY.md | 2 +- 17 files changed, 50 insertions(+), 107 deletions(-) rename Documentation/Books/Manual/Foxx/{Anatomy.mdpp => AtAGlance.mdpp} (97%) diff --git a/Documentation/Books/Manual/Foxx/Assets.mdpp b/Documentation/Books/Manual/Foxx/Assets.mdpp index 9c0f8b570e..341a84a942 100644 --- a/Documentation/Books/Manual/Foxx/Assets.mdpp +++ b/Documentation/Books/Manual/Foxx/Assets.mdpp @@ -42,4 +42,3 @@ Each entry in the `files` attribute can represent either a single file or a dire If set to `true` the file will be served with gzip-encoding if supported by the client. This can be useful when serving text files like client-side JavaScript, CSS or HTML. If a string is provided instead of an object, it will be interpreted as the *path* option. - diff --git a/Documentation/Books/Manual/Foxx/Anatomy.mdpp b/Documentation/Books/Manual/Foxx/AtAGlance.mdpp similarity index 97% rename from Documentation/Books/Manual/Foxx/Anatomy.mdpp rename to Documentation/Books/Manual/Foxx/AtAGlance.mdpp index 26bda7c085..42f018506e 100644 --- a/Documentation/Books/Manual/Foxx/Anatomy.mdpp +++ b/Documentation/Books/Manual/Foxx/AtAGlance.mdpp @@ -1,4 +1,4 @@ -!CHAPTER Foxx anatomy +!CHAPTER Foxx at a glance Each Foxx service is defined by a [JSON manifest](Manifest.md) specifying the entry point, any scripts defined by the service, possible configuration diff --git a/Documentation/Books/Manual/Foxx/Dependencies.mdpp b/Documentation/Books/Manual/Foxx/Dependencies.mdpp index 79b1fa2362..b7eb19422d 100644 --- a/Documentation/Books/Manual/Foxx/Dependencies.mdpp +++ b/Documentation/Books/Manual/Foxx/Dependencies.mdpp @@ -14,6 +14,8 @@ You can use the `node_modules` folder to bundle third-party Foxx-compatible npm Make sure to include the actual `node_modules` folder in your Foxx service bundle as ArangoDB will not do anything special to install these dependencies. Also keep in mind that bundling extraneous modules like development dependencies may bloat the file size of your Foxx service bundle. +!SUBSECTION Compatibility caveats + TODO Note about async etc !SECTION Foxx dependencies diff --git a/Documentation/Books/Manual/Foxx/GettingStarted.mdpp b/Documentation/Books/Manual/Foxx/GettingStarted.mdpp index 4f53d4b0cf..8f89d74df9 100644 --- a/Documentation/Books/Manual/Foxx/GettingStarted.mdpp +++ b/Documentation/Books/Manual/Foxx/GettingStarted.mdpp @@ -14,7 +14,7 @@ First we need to create a manifest. Create a new file called `manifest.json` and This just tells ArangoDB the service is compatible with versions 3.0.0 and later (all the way up to but not including 4.0.0), allowing older versions of ArangoDB to understand that this service likely won't work for them and newer versions what behavior to emulate should they still support it. -The little hat to the left of the version number is not a typo, it's called a "caret" and indicates the version range. Foxx uses semantic versioning (also called "semver") for most of its version handling. You can find out more about how semver works at the [official semver website][SEMVER]. +The little hat to the left of the version number is not a typo, it's called a "caret" and indicates the version range. Foxx uses semantic versioning (also called "semver") for most of its version handling. You can find out more about how semver works at the [official semver website](http://semver.org). Next we'll need to specify an entry point to our service. This is the JavaScript file that will be executed to define our service's HTTP endpoints. We can do this by adding a "main" field to our manifest: @@ -37,7 +37,7 @@ const router = createRouter(); module.context.use(router); ``` -The first line causes our file to be interpreted using [strict mode][STRICT]. All examples in the ArangoDB documentation assume strict mode, so you might want to familiarize yourself with it if you haven't encountered it before. +The first line causes our file to be interpreted using [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode). All examples in the ArangoDB documentation assume strict mode, so you might want to familiarize yourself with it if you haven't encountered it before. The second line imports the `@arangodb/foxx/router` module which provides a function for creating new Foxx routers. We're using this function to create a new `router` object which we'll be using for our service. @@ -57,7 +57,7 @@ router.get('/hello-world', function (req, res) { The `router` provides the methods `get`, `post`, etc corresponding to each HTTP verb as well as the catch-all `all`. These methods indicate that the given route should be used to handle incoming requests with the given HTTP verb (or any method when using `all`). -These methods take an optional path (if omitted, it defaults to `"/"`) as well as a request handler, which is a function taking the `req` ([request][REQUEST]) and `res` ([response][RESPONSE]) objects to handle the incoming request and generate the outgoing response. If you have used the express framework in Node.js, you may already be familiar with how this works, otherwise check out [the chapter on routes][ROUTES]. +These methods take an optional path (if omitted, it defaults to `"/"`) as well as a request handler, which is a function taking the `req` ([request](Router/Request.md)) and `res` ([response](Router/Response.md)) objects to handle the incoming request and generate the outgoing response. If you have used the express framework in Node.js, you may already be familiar with how this works, otherwise check out [the chapter on routes](Router/Endpoints.md). The object returned by the router's methods provides additional methods to attach metadata and validation to the route. We're using `summary` and `description` to document what the route does -- these aren't strictly necessary but give us some nice auto-generated documentation. The `response` method lets us additionally document the response content type and what the response body will represent. @@ -108,9 +108,9 @@ router.get('/hello/:name', function (req, res) { .description('Prints a personalized greeting.'); ``` -The first line imports the [`joi` module from npm][JOI] which comes bundled with ArangoDB. Joi is a validation library that is used throughout Foxx to define schemas and parameter types. +The first line imports the [`joi` module from npm](https://www.npmjs.com/package/joi) which comes bundled with ArangoDB. Joi is a validation library that is used throughout Foxx to define schemas and parameter types. -**Note**: You can bundle your own modules from npm by installing them in your service folder and making sure the `node_modules` folder is included in your zip archive. For more information see the section on [module dependencies in the chapter on dependencies][DEPENDENCIES]. +**Note**: You can bundle your own modules from npm by installing them in your service folder and making sure the `node_modules` folder is included in your zip archive. For more information see the section on [module dependencies in the chapter on dependencies](Dependencies.md). The `pathParam` method allows us to specify parameters we are expecting in the path. The first argument corresponds to the parameter name in the path, the second argument is a joi schema the parameter is expected to match and the final argument serves to describe the parameter in the API documentation. @@ -154,7 +154,7 @@ The `body` method works the same way as the `response` method except the schema !SECTION Creating collections -The real power of Foxx comes from interacting with the database itself. In order to be able to use a collection from within our service, we should first make sure that the collection actually exists. The right place to create collections your service is going to use is in [a *setup* script][SCRIPTS], which Foxx will execute for you when installing or updating the service. +The real power of Foxx comes from interacting with the database itself. In order to be able to use a collection from within our service, we should first make sure that the collection actually exists. The right place to create collections your service is going to use is in [a *setup* script](Scripts.md), which Foxx will execute for you when installing or updating the service. First create a new folder called "scripts" in the service folder, which will be where our scripts are going to live. For simplicity's sake, our setup script will live in a file called `setup.js` inside that folder: @@ -169,11 +169,11 @@ if (!db._collection(collectionName)) { } ``` -The script uses the [`db` object][DBOBJECT] from the `@arangodb` module, which lets us interact with the database the Foxx service was installed in and the collections inside that database. Because the script may be executed multiple times (i.e. whenever we update the service or when the server is restarted) we need to make sure we don't accidentally try to create the same collection twice (which would result in an exception); we do that by first checking whether it already exists before creating it. +The script uses the [`db` object](../Appendix/References/DBObject.md) from the `@arangodb` module, which lets us interact with the database the Foxx service was installed in and the collections inside that database. Because the script may be executed multiple times (i.e. whenever we update the service or when the server is restarted) we need to make sure we don't accidentally try to create the same collection twice (which would result in an exception); we do that by first checking whether it already exists before creating it. The `_collection` method looks up a collection by name and returns `null` if no collection with that name was found. The `_createDocumentCollection` method creates a new document collection by name (`_createEdgeCollection` also exists and works analogously for edge collections). -**Note**: Because we have hardcoded the collection name, multiple copies of the service installed alongside each other in the same database will share the same collection. Because this may not always be what you want, the [Foxx context][CONTEXT] also provides the `collectionName` method which applies a mount point specific prefix to any given collection name to make it unique to the service. It also provides the `collection` method, which behaves almost exactly like `db._collection` except it also applies the prefix before looking the collection up. +**Note**: Because we have hardcoded the collection name, multiple copies of the service installed alongside each other in the same database will share the same collection. Because this may not always be what you want, the [Foxx context](Context.md) also provides the `collectionName` method which applies a mount point specific prefix to any given collection name to make it unique to the service. It also provides the `collection` method, which behaves almost exactly like `db._collection` except it also applies the prefix before looking the collection up. Next we need to tell our service about the script by adding it to the manifest file: @@ -288,31 +288,14 @@ const keys = db._query( You now know how to create a Foxx service from scratch, how to handle user input and how to access the database from within your Foxx service to store, retrieve and query data you store inside ArangoDB. This should allow you to build meaningful APIs for your own applications but there are many more things you can do with Foxx: -* Need to go faster? Turn on [development mode][README] and hack on your code right on the server. +* Need to go faster? Turn on [development mode](README.md) and hack on your code right on the server. -* Concerned about security? You could add [authentication][AUTH] to your service to protect access to the data before it even leaves the database. +* Concerned about security? You could add [authentication](Auth.md) to your service to protect access to the data before it even leaves the database. -* Writing a single page app? You could [store some basic assets][ASSETS] right inside your Foxx service. +* Writing a single page app? You could [store some basic assets](Assets.md) right inside your Foxx service. -* Need to integrate external services? You can [make HTTP requests][REQUESTMODULE] from inside Foxx and use [queued jobs][SCRIPTS] to perform that work in the background. +* Need to integrate external services? You can [make HTTP requests](Modules.md) from inside Foxx and use [queued jobs](Scripts.md) to perform that work in the background. -* Tired of reinventing the wheel? Learn about [dependencies][DEPENDENCIES]. +* Tired of reinventing the wheel? Learn about [dependencies](Dependencies.md). -* Everything broken? You can [write tests][TESTS] to make sure your logic remains sound. - -[AUTH]: ./Auth.md -[SEMVER]: http://semver.org/ -[STRICT]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode -[JOI]: https://www.npmjs.com/package/joi -[ROUTER]: ./Router/README.md -[REQUEST]: ./Router/Request.md -[RESPONSE]: ./Router/Response.md -[ROUTES]: ./Router/Endpoints.md -[SCRIPTS]: ./Scripts.md -[ASSETS]: ./Assets.md -[README]: ./README.md -[REQUESTMODULE]: ./Modules.md -[DEPENDENCIES]: ./Dependencies.md -[CONTEXT]: ./Context.md -[DBOBJECT]: ../Appendix/References/DBObject.md -[TESTS]: ./Testing.md +* Everything broken? You can [write tests](Testing.md) to make sure your logic remains sound. diff --git a/Documentation/Books/Manual/Foxx/LegacyMode.mdpp b/Documentation/Books/Manual/Foxx/LegacyMode.mdpp index f71efda206..66c3603095 100644 --- a/Documentation/Books/Manual/Foxx/LegacyMode.mdpp +++ b/Documentation/Books/Manual/Foxx/LegacyMode.mdpp @@ -12,7 +12,7 @@ In order to mark an existing service as a legacy service, just make sure the fol } ``` -This [semantic version range][SEMVER] denotes that the service is known to work with ArangoDB 2.8.0 and supports all newer versions of ArangoDB up to but not including 3.0.0 (nor any development version of 3.0.0 and greater). +This [semantic version range](http://semver.org) denotes that the service is known to work with ArangoDB 2.8.0 and supports all newer versions of ArangoDB up to but not including 3.0.0 (nor any development version of 3.0.0 and greater). Any similar version range the does not include 3.0.0 or greater will have the same effect (e.g. `^2.5.0` will also trigger the legacy mode, as will `1.2.3`, but `>=2.8.0` will not as it indicates compatibility with *all* versions greater or equal 2.8.0, not just those within the 2.x version range). @@ -74,5 +74,3 @@ As built-in support for CoffeeScript was removed in 3.0 any service using Coffee The `@arangodb/request` module when used with the `json` option previously overwrote the string in the `body` property of the response object of the response with the parsed JSON body. In 2.8 this was changed so the parsed JSON body is added as the `json` property of the response object in addition to overwriting the `body` property. In 3.0 and later (including legacy mode) the `body` property is no longer overwritten and must use the `json` property instead. Note that this only affects code using the `json` option when making the request. Additionally, any feature not supported in 2.8 will also not work in legacy mode. When migrating from an older version of ArangoDB it is a good idea to migrate to ArangoDB 2.8 first for an easier upgrade path. - -[SEMVER]: http://semver.org/ diff --git a/Documentation/Books/Manual/Foxx/Manifest.mdpp b/Documentation/Books/Manual/Foxx/Manifest.mdpp index a211b6cdc3..24733c8ed4 100644 --- a/Documentation/Books/Manual/Foxx/Manifest.mdpp +++ b/Documentation/Books/Manual/Foxx/Manifest.mdpp @@ -4,7 +4,7 @@ Every service comes with a `manifest.json` file providing metadata. The followin * **configuration**: `Object` (optional) - An object defining the [configuration options][CONFIG] this service requires. + An object defining the [configuration options](Configuration.md) this service requires. * **defaultDocument**: `string` (optional) @@ -29,11 +29,11 @@ Every service comes with a `manifest.json` file providing metadata. The followin * **dependencies**: `Object` (optional) and **provides**: `Object` (optional) - Objects specifying other services this service has as [dependencies][DEPS] and what dependencies it can provide to other services. + Objects specifying other services this service has as [dependencies](Dependencies.md) and what dependencies it can provide to other services. * **engines**: `Object` (optional) - An object indicating the [semantic version ranges][SEMVER] of ArangoDB (or compatible environments) the service will be compatible with, e.g.: + An object indicating the [semantic version ranges](http://semver.org) of ArangoDB (or compatible environments) the service will be compatible with, e.g.: ```json "engines": { @@ -45,7 +45,7 @@ Every service comes with a `manifest.json` file providing metadata. The followin * **files**: `Object` (optional) - An object defining [file assets][ASSETS] served by this service. + An object defining [file assets](Assets.md) served by this service. * **lib**: `string` (Default: `"."`) @@ -71,11 +71,11 @@ Every service comes with a `manifest.json` file providing metadata. The followin * **scripts**: `Object` (optional) - An object defining [named scripts][SCRIPTS] provided by this service, which can either be used directly or as queued jobs by other services. + An object defining [named scripts](Scripts.md) provided by this service, which can either be used directly or as queued jobs by other services. * **tests**: `string` or `Array` (optional) - A path or list of paths of JavaScript [tests][TESTING] provided for this service. + A path or list of paths of JavaScript [tests](Testing.md) provided for this service. Additionally manifests can provide the following metadata: @@ -97,7 +97,7 @@ Additionally manifests can provide the following metadata: * **license**: `string` (optional) - A string identifying the license under which the service is published, ideally in the form of an [SPDX license identifier][SPDX]. This will be shown in the web interface. + A string identifying the license under which the service is published, ideally in the form of an [SPDX license identifier](https://spdx.org/licenses). This will be shown in the web interface. * **name**: `string` (optional) @@ -109,7 +109,7 @@ Additionally manifests can provide the following metadata: * **version**: `string` (optional) - The version number of the Foxx service. The version number must follow the [semantic versioning format][SEMVER]. This will be shown in the web interface. + The version number of the Foxx service. The version number must follow the [semantic versioning format](http://semver.org). This will be shown in the web interface. **Examples** @@ -146,11 +146,3 @@ Additionally manifests can provide the following metadata: "tests": "dist/**.spec.js" } ``` - -[SEMVER]: http://semver.org/ -[SPDX]: https://spdx.org/licenses/ -[CONFIG]: ./Configuration.md -[DEPS]: ./Dependencies.md -[ASSETS]: ./Assets.md -[SCRIPTS]: ./Scripts.md -[TESTING]: ./Testing.md diff --git a/Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp b/Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp index d3135e1b74..3af91a1ab9 100644 --- a/Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp +++ b/Documentation/Books/Manual/Foxx/Router/Endpoints.mdpp @@ -143,7 +143,7 @@ If the endpoint is a child router, all routes of that router will use this respo * **status**: `number | string` (Default: `200` or `204`) - HTTP status code the response applies to. If a string is provided instead of a numeric status code it will be used to look up a numeric status code using the [statuses][STATUSES] module. + HTTP status code the response applies to. If a string is provided instead of a numeric status code it will be used to look up a numeric status code using the [statuses](https://github.com/jshttp/statuses) module. * **model**: `Model | Schema | null` (optional) @@ -230,7 +230,7 @@ This method only affects the generated API documentation and has not other effec * **status**: `number | string` - HTTP status code for the error (e.g. `400` for "bad request"). If a string is provided instead of a numeric status code it will be used to look up a numeric status code using the [statuses][STATUSES] module. + HTTP status code for the error (e.g. `400` for "bad request"). If a string is provided instead of a numeric status code it will be used to look up a numeric status code using the [statuses](https://github.com/jshttp/statuses) module. * **description**: `string` (optional) @@ -329,5 +329,3 @@ Returns the endpoint. router.get(/* ... */) .deprecated(); ``` - -[STATUSES]: https://github.com/jshttp/statuses diff --git a/Documentation/Books/Manual/Foxx/Router/README.mdpp b/Documentation/Books/Manual/Foxx/Router/README.mdpp index 5bc0bfb2e1..84950dd1d8 100644 --- a/Documentation/Books/Manual/Foxx/Router/README.mdpp +++ b/Documentation/Books/Manual/Foxx/Router/README.mdpp @@ -4,7 +4,7 @@ TODO -Routers need to be mounted to expose their HTTP routes. See [service context][CONTEXT]. +Routers need to be mounted to expose their HTTP routes. See [service context](../Context.md). !SECTION Creating a router @@ -32,7 +32,7 @@ TODO * **path**: `string` (Default: `"/"`) - The path of the request handler relative to the base path the Router is mounted at. If omitted, the request handler will handle requests to the base path of the Router. For information on defining dynamic routes see the section on path parameters in the [chapter on router endpoints][ENDPOINTS]. + The path of the request handler relative to the base path the Router is mounted at. If omitted, the request handler will handle requests to the base path of the Router. For information on defining dynamic routes see the section on path parameters in the [chapter on router endpoints](Endpoints.md). * **handler**: `Function` @@ -48,7 +48,7 @@ TODO * **name**: `string` (optional) - A name that can be used to generate URLs for the endpoint. For more information see the `reverse` method of the [request object][REQUEST]. + A name that can be used to generate URLs for the endpoint. For more information see the `reverse` method of the [request object](Request.md). TODO @@ -70,10 +70,6 @@ TODO * **name**: `string` (optional) - A name that can be used to generate URLs for endpoints of this router. For more information see the `reverse` method of the [request object][REQUEST]. Has no effect if *handler* is a Middleware. + A name that can be used to generate URLs for endpoints of this router. For more information see the `reverse` method of the [request object](Request.md). Has no effect if *handler* is a Middleware. TODO - -[CONTEXT]: ../Context.md -[ENDPOINTS]: ./Endpoints.md -[REQUEST]: ./Request.md diff --git a/Documentation/Books/Manual/Foxx/Router/Request.mdpp b/Documentation/Books/Manual/Foxx/Router/Request.mdpp index 105ff38d08..ddfdc4082a 100644 --- a/Documentation/Books/Manual/Foxx/Router/Request.mdpp +++ b/Documentation/Books/Manual/Foxx/Router/Request.mdpp @@ -16,7 +16,7 @@ The request object specifies the following properties: * **context**: `Context` - The [service context][CONTEXT] in which the router was mounted (rather than the context in which the route was defined). + The [service context](../Context.md) in which the router was mounted (rather than the context in which the route was defined). TODO @@ -141,7 +141,7 @@ The request object specifies the following properties: `req.acceptsLanguages(...languages): string | false` -These methods wrap the corresponding content negotiation methods of the [accepts module][ACCEPTS] for the current request. +These methods wrap the corresponding content negotiation methods of the [accepts module](https://github.com/jshttp/accepts) for the current request. **Examples** @@ -205,7 +205,7 @@ TODO `req.is(...types): string` -This method wraps the (request body) content type detection method of the [type-is module][TYPEIS] for the current request. +This method wraps the (request body) content type detection method of the [type-is module](https://github.com/jshttp/type-is) for the current request. **Arguments** @@ -257,7 +257,7 @@ TODO `req.range([size]): Ranges | number` -This method wraps the range header parsing method of the [range-parser module][RANGEPARSER] for the current request. +This method wraps the range header parsing method of the [range-parser module](https://github.com/jshttp/range-parser) for the current request. **Arguments** @@ -277,8 +277,3 @@ const ranges = req.range(100); console.log(ranges); // [{start: 40, end: 80}] console.log(ranges.type); // "bytes" ``` - -[CONTEXT]: ../Context.md -[ACCEPTS]: https://github.com/jshttp/accepts -[RANGEPARSER]: https://github.com/jshttp/range-parser -[TYPEIS]: https://github.com/jshttp/type-is diff --git a/Documentation/Books/Manual/Foxx/Sessions/README.mdpp b/Documentation/Books/Manual/Foxx/Sessions/README.mdpp index b423bbe740..586a890f91 100644 --- a/Documentation/Books/Manual/Foxx/Sessions/README.mdpp +++ b/Documentation/Books/Manual/Foxx/Sessions/README.mdpp @@ -2,7 +2,7 @@ `const sessionMiddleware = require('@arangodb/foxx/sessions');` -The session middleware adds the `session` and `sessionStorage` properties to the [request object][REQUEST] and deals with serializing and deserializing the session as well as extracting session identifiers from incoming requests and injecting them into outgoing responses. +The session middleware adds the `session` and `sessionStorage` properties to the [request object](../Router/Request.md) and deals with serializing and deserializing the session as well as extracting session identifiers from incoming requests and injecting them into outgoing responses. **Examples** @@ -48,7 +48,7 @@ Creates a session middleware. The storage is also exposed as the `sessionStorage` on all request objects and as the `storage` property of the middleware. - If a string or collection is passed instead of a Storage, it will be used to create a [Collection Storage][COLLECTIONSTORAGE]. + If a string or collection is passed instead of a Storage, it will be used to create a [Collection Storage](Storages/Collection.md). * **transport**: `Transport | Array` @@ -56,17 +56,12 @@ Creates a session middleware. The transports are also exposed as the `transport` property of the middleware. - If the string `"cookie"` is passed instead of a Transport, the [Cookie Transport][COOKIETRANSPORT] will be used with the default settings instead. + If the string `"cookie"` is passed instead of a Transport, the [Cookie Transport](Transports/Cookie.md) will be used with the default settings instead. - If the string `"header"` is passed instead of a Transport, the [Header Transport][HEADERTRANSPORT] will be used with the default settings instead. + If the string `"header"` is passed instead of a Transport, the [Header Transport](Transports/Header.md) will be used with the default settings instead. * **autoCreate**: `boolean` (Default: `true`) If enabled the session storage's `new` method will be invoked to create an empty session whenever the transport failed to return a session for the incoming request. Otherwise the session will be initialized as `null`. Returns the session middleware. - -[COLLECTIONSTORAGE]: ./Storages/Collection.md -[COOKIETRANSPORT]: ./Transports/Cookie.md -[HEADERTRANSPORT]: ./Transports/Header.md -[REQUEST]: ../Router/Request.md diff --git a/Documentation/Books/Manual/Foxx/Sessions/Storages/Collection.mdpp b/Documentation/Books/Manual/Foxx/Sessions/Storages/Collection.mdpp index 6782495a04..087f8ef4fd 100644 --- a/Documentation/Books/Manual/Foxx/Sessions/Storages/Collection.mdpp +++ b/Documentation/Books/Manual/Foxx/Sessions/Storages/Collection.mdpp @@ -8,7 +8,7 @@ The collection session storage persists sessions to a collection in the database `collectionStorage(options): Storage` -Creates a [Storage][STORAGES] that can be used in the sessions middleware. +Creates a [Storage](README.md) that can be used in the sessions middleware. **Arguments** @@ -70,5 +70,3 @@ Removes the session from the collection. Has no effect if the session was alread A session object. Returns `true` if the session was removed or `false` if it had no effect. - -[STORAGES]: ./README.md diff --git a/Documentation/Books/Manual/Foxx/Sessions/Storages/JWT.mdpp b/Documentation/Books/Manual/Foxx/Sessions/Storages/JWT.mdpp index 93da631d91..fdd30caf74 100644 --- a/Documentation/Books/Manual/Foxx/Sessions/Storages/JWT.mdpp +++ b/Documentation/Books/Manual/Foxx/Sessions/Storages/JWT.mdpp @@ -20,7 +20,7 @@ module.context.use(sessions); `jwtStorage(options): Storage` -Creates a [Storage][STORAGES] that can be used in the sessions middleware. +Creates a [Storage](README.md) that can be used in the sessions middleware. **Note:** while the "none" algorithm (i.e. no signature) is supported this dummy algorithm provides no security and allows clients to make arbitrary modifications to the payload and should not be used unless you are certain you specifically need it. @@ -56,5 +56,3 @@ Creates a [Storage][STORAGES] that can be used in the sessions middleware. If set to `false` the signature will not be verified but still generated (unless using the "none" algorithm). If a string is passed instead of an options object it will be interpreted as the *secret* option. - -[STORAGES]: ./README.md diff --git a/Documentation/Books/Manual/Foxx/Sessions/Transports/Cookie.mdpp b/Documentation/Books/Manual/Foxx/Sessions/Transports/Cookie.mdpp index dc1557dba1..3a95cb11f6 100644 --- a/Documentation/Books/Manual/Foxx/Sessions/Transports/Cookie.mdpp +++ b/Documentation/Books/Manual/Foxx/Sessions/Transports/Cookie.mdpp @@ -25,7 +25,7 @@ module.context.use(sessions); `cookieTransport([options]): Transport` -Creates a [Transport][TRANSPORT] that can be used in the sessions middleware. +Creates a [Transport](README.md) that can be used in the sessions middleware. **Arguments** @@ -43,13 +43,10 @@ Creates a [Transport][TRANSPORT] that can be used in the sessions middleware. * **algorithm**: `string` (optional) - The algorithm used to sign and verify the cookie. If no algorithm is specified, the cookie will not be signed or verified. See the [cookie method on the response object][RESPONSE]. + The algorithm used to sign and verify the cookie. If no algorithm is specified, the cookie will not be signed or verified. See the [cookie method on the response object](../../Router/Response.md). * **secret**: `string` (optional) Secret to use for the signed cookie. Will be ignored if no algorithm is provided. If a string is passed instead of an options object, it will be interpreted as the *name* option. - -[RESPONSE]: ../../Router/Response.md -[TRANSPORT]: ./README.md diff --git a/Documentation/Books/Manual/Foxx/Sessions/Transports/Header.mdpp b/Documentation/Books/Manual/Foxx/Sessions/Transports/Header.mdpp index c60eae87d2..a5d56bbe20 100644 --- a/Documentation/Books/Manual/Foxx/Sessions/Transports/Header.mdpp +++ b/Documentation/Books/Manual/Foxx/Sessions/Transports/Header.mdpp @@ -18,7 +18,7 @@ module.context.use(sessions); `headerTransport([options]): Transport` -Creates a [Transport][TRANSPORT] that can be used in the sessions middleware. +Creates a [Transport](README.md) that can be used in the sessions middleware. **Arguments** @@ -31,5 +31,3 @@ Creates a [Transport][TRANSPORT] that can be used in the sessions middleware. Name of the header that contains the session identifier (not case sensitive). If a string is passed instead of an options object, it will be interpreted as the *name* option. - -[TRANSPORT]: ./README.md diff --git a/Documentation/Books/Manual/Foxx/Sessions/Transports/README.mdpp b/Documentation/Books/Manual/Foxx/Sessions/Transports/README.mdpp index 3c220b32c7..c03a276250 100644 --- a/Documentation/Books/Manual/Foxx/Sessions/Transports/README.mdpp +++ b/Documentation/Books/Manual/Foxx/Sessions/Transports/README.mdpp @@ -12,7 +12,7 @@ TODO * **request**: `Request` - [Request object][REQUEST] to extract a session identifier from. + [Request object](../../Router/Request.md) to extract a session identifier from. TODO @@ -30,7 +30,7 @@ TODO * **response**: `Response` - [Response object][RESPONSE] to attach a session identifier to. + [Response object](../../Router/Response.md) to attach a session identifier to. * **sid**: `string` @@ -59,6 +59,3 @@ TODO **Examples** TODO - -[REQUEST]: ../../Router/Request.md -[RESPONSE]: ../../Router/Response.md diff --git a/Documentation/Books/Manual/Foxx/Users.mdpp b/Documentation/Books/Manual/Foxx/Users.mdpp index 4a6a8041e0..4eabc28a71 100644 --- a/Documentation/Books/Manual/Foxx/Users.mdpp +++ b/Documentation/Books/Manual/Foxx/Users.mdpp @@ -2,9 +2,9 @@ Foxx does not provide any user management out of the box but it is very easy to roll your own solution: -The [session middleware][SESSIONS] provides mechanisms for adding session logic to your service, using e.g. a collection or JSON Web Tokens to store the sessions between requests. +The [session middleware](Sessions/README.md) provides mechanisms for adding session logic to your service, using e.g. a collection or JSON Web Tokens to store the sessions between requests. -The [auth module][AUTH] provides utilities for basic password verification and hashing. +The [auth module](Auth.md) provides utilities for basic password verification and hashing. The following example service demonstrates how user management can be implemented using these basic building blocks. @@ -120,6 +120,3 @@ router.post('/signup', function (req, res) { }).required(), 'Credentials') .description('Creates a new user and logs them in.'); ``` - -[AUTH]: ./Auth.md -[SESSIONS]: ./Sessions/README.md diff --git a/Documentation/Books/Manual/SUMMARY.md b/Documentation/Books/Manual/SUMMARY.md index 18b2e3e866..dad84d6853 100644 --- a/Documentation/Books/Manual/SUMMARY.md +++ b/Documentation/Books/Manual/SUMMARY.md @@ -62,7 +62,7 @@ * [Working with Edges](Graphs/Edges/README.md) # * [Foxx Microservices](Foxx/README.md) - * [Foxx Anatomy](Foxx/Anatomy.md) + * [At a glance](Foxx/AtAGlance.md) * [Getting started](Foxx/GettingStarted.md) * [Service manifest](Foxx/Manifest.md) * [Service context](Foxx/Context.md)