1
0
Fork 0
arangodb/arangod/Documentation/user-manual.dox

925 lines
32 KiB
Plaintext

////////////////////////////////////////////////////////////////////////////////
/// @brief user guide guide
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- USER MANUAL
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @page UserManual ArangoDB's User Manual (@VERSION)
///
/// @NAVIGATE{Upgrading,Home,DbaManual}
///
/// @if LATEX
/// <ul>
/// <li>@ref FirstStepsArangoDB</li>
/// <li>@ref UserManualArangosh</li>
/// <li>@ref ShellCollection</li>
/// <li>@ref ShellDocument</li>
/// <li>@ref ShellEdge</li>
/// <li>@ref SimpleQueries</li>
/// <li>@ref Aql</li>
/// <li>@ref UserManualActions</li>
///
/// @latexonly\appendix@endlatexonly
/// <li>@ref CommandLine</li>
/// <li>@ref Glossary</li>
/// </ul>
/// @else
/// @copydetails FirstStepsArangoDBTOC
/// @copydetails UserManualArangoshTOC
/// @copydetails ShellCollectionTOC
/// @copydetails ShellDocumentTOC
/// @copydetails ShellEdgeTOC
/// @copydetails SimpleQueriesTOC
/// @copydetails AqlTOC
/// @copydetails UserManualActionsTOC
/// @copydetails CommandLineTOC
/// @endif
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- USER MANUAL ARANGOSH
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @page UserManualArangoshTOC
///
/// <ul>
/// <li>@ref UserManualArangosh
/// </li>
/// </ul>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @page UserManualArangosh The Arango Shell
///
/// @EMBEDTOC{UserManualArangoshTOC}
///
/// @section UserManualArangoshOutput Arango Shell Output
/////////////////////////////////////////////////////////
///
/// In general the Arango Shells prints its as output to standard output channel
/// using the JSON stringifier.
///
/// @code
/// arangosh> db.five.all().toArray();
/// [{ _id : "2223655/3665447", _rev : 3665447, name : "one" },
/// { _id : "2223655/3730983", _rev : 3730983, name : "two" },
/// { _id : "2223655/3862055", _rev : 3862055, name : "four" },
/// { _id : "2223655/3993127", _rev : 3993127, name : "three" }]
/// @endcode
///
/// @CLEARPAGE
/// @FUN{start_pretty_print()}
///
/// While the standard JSON stringifier is very concise it is hard to read.
/// Calling the function @FN{start_pretty_print} will enable the pretty printer
/// which formats the output in a human readable way.
///
/// @code
/// arangosh> start_pretty_print();
/// using pretty printing
/// arangosh> db.five.all().toArray();
/// [
/// {
/// _id : "2223655/3665447",
/// _rev : 3665447,
/// name : "one"
/// },
/// {
/// _id : "2223655/3730983",
/// _rev : 3730983,
/// name : "two"
/// },
/// {
/// _id : "2223655/3862055",
/// _rev : 3862055,
/// name : "four"
/// },
/// {
/// _id : "2223655/3993127",
/// _rev : 3993127,
/// name : "three"
/// }
/// ]
/// @endcode
///
/// @CLEARPAGE
/// @FUN{stop_pretty_print()}
///
/// The functions disable the pretty printer, switching back to the standard
/// JSON output format.
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- USER MANUAL ACTIONS
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @page UserManualActionsTOC
///
/// <ul>
/// <li>@ref UserManualActions
/// <ul>
/// <li>@ref UserManualActionsIntro</li>
/// <li>@ref UserManualActionsHelloWorld</li>
/// <li>@ref UserManualActionsMatches
/// <ul>
/// <li>@ref UserManualActionsMatchesExact</li>
/// <li>@ref UserManualActionsMatchesPrefix</li>
/// <li>@ref UserManualActionsMatchesParameterized</li>
/// <li>@ref UserManualActionsMatchesConstraint</li>
/// <li>@ref UserManualActionsMatchesOptional</li>
/// <li>@ref UserManualActionsMatchesMethod</li>
/// <li>@ref UserManualActionsMatching</li>
/// </ul>
/// </li>
/// <li>@ref UserManualActionsHelloJson</li>
/// <li>@ref UserManualActionsContent
/// <ul>
/// <li>@ref UserManualActionsContentStatic</li>
/// <li>@ref UserManualActionsContentAction</li>
/// <li>@ref UserManualActionsContentController</li>
/// <li>@ref UserManualActionsContentPrefix</li>
/// </ul>
/// </li>
/// <li>@ref UserManualActionsReqRes</li>
/// <li>@ref UserManualActionsModify</li>
/// <li>@ref UserManualActionsHandlers</li>
/// <li>@ref UserManualActionsAdvanced
/// <ul>
/// <li>@ref UserManualActionsAdvancedRedirects</li>
/// <li>@ref UserManualActionsAdvancedBundles</li>
/// <li>@ref UserManualActionsAdvancedMiddleware</li>
/// </ul>
/// </li>
/// </ul>
/// </li>
/// </ul>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @page UserManualActions Arango Actions
///
/// Please note, that user Actions in ArangoDB are still preliminary and details
/// are subject to change.
///
/// @EMBEDTOC{UserManualActionsTOC}
///
/// @section UserManualActionsIntro Introduction to User Actions
////////////////////////////////////////////////////////////////
///
/// In some ways the communication layer of the ArangoDB server behaves like a
/// Web server. Unlike a Web server, it normally responds to HTTP requests by
/// delivering JSON objects. Remember, documents in the database are just JSON
/// objects. So, most of the time the HTTP response will contain a JSON document
/// from the database as body. You can extract the documents stored in the
/// database using HTTP @LIT{GET}. You can store documents using HTTP
/// @LIT{POST}.
///
/// However, there is something more. You can write small sniplets - so called
/// actions - to extend the database. The idea of actions is that sometimes it
/// is better to store parts of the business logic within AnrangoDB.
///
/// The simplest example is the age of a person. Assume you store information
/// about people in your database. It is an anti-pattern to store the age,
/// because it changes every now and then. Therefore, you normally store the
/// birthday and let the client decide what to do with it. However, if you have
/// many different clients, it might be easier to enrich the person document
/// with the age using actions once on the server side.
///
/// Or, for instance, if you want to apply some statistics to large data-sets
/// and you cannot easily express this as query. You can define a action instead
/// of transferring the whole data to the client and do the computation on the
/// client.
///
/// Actions are also useful if you want to restrict and filter data according to
/// some complex permission system.
///
/// The ArangoDB server can deliver all kinds of information, JSON being only
/// one possible format. You can also generate HTML or images. However, a Web
/// server is normally better suited for the task as it also implements various
/// caching strategies, language selection, compression and so on. Having said
/// that, there are still situations where it might be suitable to use the
/// ArangoDB to deliver HTML pages - static or dynamic. An simple example is the
/// built-in administration interface. You can access it using any modern
/// browser and there is no need for a separate Apache or IIS.
///
/// The following sections will explain actions within ArangoDB and show how to
/// define them. The examples start with delivering static HTML pages - even if
/// this is not the primary use-case for actions. The later sections will then
/// show you how to code some pieces of your business logic and return JSON
/// objects.
///
/// The interface is loosely modelled after the JavaScript classes for HTTP
/// request and responses found in node.js and the middleware/routing aspects
/// of connect.js and express.js.
///
/// Note that unlike node.js, ArangoDB is multi-threaded and there is no easy
/// way to share state between queries inside the JavaScript engine. If such
/// state information is required, you need to use the database itself.
///
/// @section UserManualActionsHelloWorld A Hello World Example
//////////////////////////////////////////////////////////////
///
/// The client API or browser sends a HTTP request to the ArangoDB server and
/// the server returns a HTTP response to the client. A HTTP requests consists
/// of a method, normally @LIT{GET} or @LIT{POST} when using a browser, and a
/// request path like @LIT{/hello/world}. For a real Web server there are a zillion
/// of other thing to consider, we will ignore this for the moment. The HTTP
/// response contains a content type, describing how to interpret the returned
/// data, and the data itself.
///
/// In the following example, we want to define an action in ArangoDB, so that the
/// server returns the HTML document
///
/// @code
/// <html>
/// <body>
/// Hello World
/// </body>
/// </html>
/// @endcode
///
/// if asked @LIT{GET /hello/world}.
///
/// The server needs to know what function to call or what document to deliver
/// if it receives a request. This is called routing. All the routing information
/// of ArangoDB is stored in a collection @LIT{_routing}. Each entry in this
/// collections describes how to deal with a particular request path.
///
/// For the above example, add the following document to the @{_routing}
/// collection:
///
/// @code
/// arangosh> db._routing.save({
/// ........> url: { match: "/hello/world" },
/// ........> content: {
/// ........> contentType: "text/html",
/// ........> body: "<html><body>Hello World</body></html>" }});
/// @endcode
///
/// In order to activate the new routing, you must either restart the server
/// or call the internal reload function.
///
/// @code
/// arangosh> require("internal").reloadRouting()
/// @endcode
///
/// Now use the browser and access
///
/// @LIT{http://localhost:8529/hello/world}
///
/// You should see the @LIT{Hello World} in our browser.
///
/// @section UserManualActionsMatches Matching an URL
/////////////////////////////////////////////////////
///
/// There are a lot of options for the @LIT{url} attribute. If you define
/// different routing for the same path, then the following simple rule is
/// applied in order to determine which match wins: If there are two matches,
/// then the more specific wins. I. e, if there is a wildcard match and an exact
/// match, the exact match is prefered. If there is a short and a long match,
/// the longer match wins.
///
/// @subsection UserManualActionsMatchesExact Exact Match
///
/// If the definition is
///
/// @code
/// { url: { match: "/hello/world" } }
/// @endcode
///
/// then the match must be exact. Only the request for @LIT{/hello/world} will
/// match, everything else, e. g. @LIT{/hello/world/my} or @LIT{/hello/world2},
/// will not match.
///
/// The following definition is a short-cut for an exact match.
///
/// @code
/// { url: "/hello/world" }
/// @endcode
///
/// @subsection UserManualActionsMatchesPrefix Prefix Match
///
/// If the definition is
///
/// @code
/// { url: { match: "/hello/world/*" } }
/// @endcode
///
/// then the match can be a prefix match. The requests for @LIT{/hello/world},
/// @LIT{/hello/world/my}, and @LIT{/hello/world/how/are/you} will all
/// match. However @LIT{/hello/world2} does not match. Prefix matches within an
/// URL part, i. e. @LIT{/hello/world*}, are not allowed. The wildcard must
/// occur at the end, i. e.
///
/// @code
/// /hello/*/world
/// @endcode
///
/// is also disallowed.
///
/// If you define two routes
///
/// @code
/// { url: { match: "/hello/world/*" } }
/// { url: { match: "/hello/world/emil" } }
/// @endcode
///
/// then the second route will be used for @LIT{/hello/world/emil} because it is
/// more specific.
///
/// @subsection UserManualActionsMatchesParameterized Parameterized Match
///
/// A parameterized match is similar to a prefix match, but the parameters are
/// also allowed inside the URL path.
///
/// If the definition is
///
/// @code
/// { url: { match: "/hello/:name/world" } }
/// @endcode
///
/// then the URL must have three parts, the first part being @LIT{hello} and the
/// third part @LIT{world}. For example, @LIT{/hello/emil/world} will match,
/// while @LIT{/hello/emil/meyer/world} will not.
///
/// @subsection UserManualActionsMatchesConstraint Constraint Match
///
/// A constraint match is similar to a parameterized match, but the parameters
/// can carry constraints.
///
/// If the definition is
///
/// @code
/// { url: { match: "/hello/:name/world", constraint: { name: "/[a-z]+/" } }
/// @endcode
///
/// then the URL must have three parts, the first part being @LIT{hello} and the
/// third part @LIT{world}. The second part must be all lowercase.
///
/// It is possible to use more then one constraint for the same URL part.
///
/// @code
/// { url: { match: "/hello/:name|:id/world",
/// constraint: { name: "/[a-z]+/", id: "/[0-9]+/" } }
/// @endcode
///
/// @subsection UserManualActionsMatchesOptional Optional Match
///
/// An optional match is similar to a parameterized match, but the last
/// parameter is optional.
///
/// If the definition is
///
/// @code
/// { url: { match: "/hello/:name?", constraint: { name: "/[a-z]+/" } }
/// @endcode
///
/// then the URL @LIT{/hello} and @LIT{/hello/emil} will match.
///
/// If the definitions are
///
/// @code
/// { url: { match: "/hello/world" } }
/// { url: { match: "/hello/:name", constraint: { name: "/[a-z]+/" } }
/// { url: { match: "/hello/*" } }
/// @endcode
///
/// then the URL @LIT{/hello/world} will be matched by the first route, because it
/// is the most specific. The URL @LIT{/hello/you} will be matched by the second
/// route, because it is more specific than the prefix match.
///
/// @subsection UserManualActionsMatchesMethod Method Restriction
///
/// You can restrict the match to specific methods.
///
/// If the definition is
///
/// @code
/// { url: { match: "/hello/world", methods: [ "post", "put" ] }
/// @endcode
///
/// then only @LIT{POST} and @LIT{PUT} requests will match.
///
/// @subsection UserManualActionsMatching More on Matching
///
/// Remember that the more specific match wins.
///
/// - A match without parameter or wildcard is more specific than a match with
/// parameters or wildcard.
/// - A match with parameter is more specific than a match with a wildcard.
/// - If there is more than one parameter, specificity is applied from left to
/// right.
///
/// Consider the following definitions
///
/// @code
/// (1) { url: { match: "/hello/world" } }
/// (2) { url: { match: "/hello/:name", constraint: { name: "/[a-z]+/" } }
/// (3) { url: { match: "/:something/world" }
/// (4) { url: { match: "/hello/*" } }
/// @endcode
///
/// Then
///
/// - @LIT{/hello/world} is match by (1)
/// - @LIT{/hello/emil} is match by (2)
/// - @LIT{/your/world} is match by (3)
/// - @LIT{/hello/you} is match by (4)
///
/// You can write the following document into the @LIT{_routing} collection
/// to test the above examples.
///
/// @code
/// {
/// routes: [
/// { url: { match: "/hello/world" }, content: "route 1" },
/// { url: { match: "/hello/:name|:id", constraint: { name: "/[a-z]+/", id: "/[0-9]+/" } }, content: "route 2" },
/// { url: { match: "/:something/world" }, content: "route 3" },
/// { url: { match: "/hello/*" }, content: "route 4" },
/// ]
/// }
/// @endcode
///
/// @section UserManualActionsHelloJson A Hello World Example for JSON
//////////////////////////////////////////////////////////////////////
///
/// If you change the example slightly, then a JSON object will be delivered.
///
/// @code
/// arangosh> db._routing.save({
/// ........> url: "/hello/json",
/// ........> content: {
/// ........> contentType: "application/json",
/// ........> body: "{ \"hello\" : \"world\" }" }});
/// arangosh> require("internal").reloadRouting()
/// @endcode
///
/// Again check with your browser
///
/// @LIT{http://localhost:8529/hello/json}
///
/// Depending on your browser and installed add-ons you will either see the
/// JSON object or a download dialog. If your browser wants to open an external
/// application to display the JSON object, you can change the @LIT{contentType}
/// to @LIT{"text/plain"} for the example. This makes it easier to check the
/// example using a browser. Or use @LIT{curl} to access the server.
///
/// @code
/// bash> curl "http://127.0.0.1:8529/hello/json" && echo
/// { "hello" : "world" }
/// @endcode
///
/// @section UserManualActionsContent Delivering Content
////////////////////////////////////////////////////////
///
/// There are a lot of different ways on how to deliver content. We have already
/// seen the simplest one, where static content is delivered. The fun, however,
/// starts when delivering dynamic content.
///
/// @subsection UserManualActionsContentStatic Static Content
///
/// You can specify a body and a content-type.
///
/// @code
/// { content: {
/// contentType: "text/html",
/// body: "<html><body>Hallo World</body></html>"
/// }
/// }
/// @endcode
///
/// If the content type is @LIT{text/plain} then you can use the short-cut
///
/// @code
/// { content: "Hallo World" }
/// @endcode
///
/// @subsection UserManualActionsContentAction A Simple Action
///
/// The simplest dynamic action is:
///
/// @code
/// { action: { controller: "org/arangodb/actions", do: "echoRequest" } }
/// @endcode
///
/// It is not possible to store functions directly in the routing table, but you
/// can call functions defined in modules. In the above example the function can
/// be accessed from JavaScript as:
///
/// @LIT{require("org/arangodb/actions").echoRequest}
///
/// The function @LIT{echoRequest} is pre-defined. It takes the request objects
/// and echos it in the response.
///
/// The signature of such a function must be
///
/// @code
/// function (req, res, options, next)
/// @endcode
///
/// For example
///
/// @code
/// arangosh> db._routing.save({
/// ........> url: "/hello/echo",
/// ........> action: { controller: "org/arangodb/actions", do: "echoRequest" } });
/// @endcode
///
/// Reload the routing and check
///
/// @LIT{http://127.0.0.1:8529/hello/echo}
///
/// You should see something like
///
/// @code
/// {
/// "request": {
/// "path": "/hello/echo",
/// "headers": {
/// "accept-encoding": "gzip, deflate",
/// "accept-language": "de-de,de;q=0.8,en-us;q=0.5,en;q=0.3",
/// "connection": "keep-alive",
/// "content-length": "0",
/// "host": "localhost:8529",
/// "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0"
/// },
/// "requestType": "GET",
/// "parameters": { }
/// },
/// "options": { }
/// }
/// @endcode
///
/// The request might contain @LIT{path}, @LIT{prefix}, @LIT{suffix}, and
/// @LIT{urlParameters} attributes. @LIT{path} is the complete path as supplied
/// by the user and always available. If a prefix was matched, then this prefix
/// is stored in the attribute @LIT{prefix} and the remaining URL parts are
/// stored as an array in @LIT{suffix}. If one or more parameters were matched,
/// then the parameter values are stored in @LIT{urlParameters}.
///
/// For example, if the url description is
///
/// @code
/// { url: { match: "/hello/:name/:action" } }
/// @endcode
///
/// and you request the path @LIT{/hello/emil/jump}, then the request object
/// will contain the following attribute
///
/// @code
/// urlParameters: { name: "emil", action: "jump" } }
/// @endcode
///
/// @subsection UserManualActionsContentController Action Controller
///
/// As an alternative to the simple action, you can use controllers. A
/// controller is a module, defines the function @LIT{get}, @LIT{put},
/// @LIT{post}, @LIT{delete}, @LIT{head}, @LIT{patch}. If a request of
/// the corresponding type is matched, the function will be called.
///
/// For example
///
/// @code
/// arangosh> db._routing.save({
/// ........> url: "/hello/echo",
/// ........> action: { controller: "org/arangodb/actions/echoController" } });
/// @endcode
///
/// @subsection UserManualActionsContentPrefix Prefix Action Controller
///
/// The controller is selected when the definition is read. There is a
/// more flexible, but slower and maybe insecure variant, the prefix
/// controller.
///
/// Assume that the url is a prefix match
///
/// @code
/// { url: { match: /hello/*" } }
/// @endcode
///
/// You can use
///
/// @code
/// { action: { prefixController: "org/arangodb/actions" } }
/// @endcode
///
/// to define a prefix controller. If the URL @LIT{/hello/echoController} is
/// given, then the module @LIT{org/arangodb/actions/echoController} is used.
///
/// If you use an prefix controller, you should make certain that no unwanted
/// actions are available under the prefix.
///
/// The definition
///
/// @code
/// { action: "org/arangodb/actions" }
/// @endcode
///
/// is a short-cut for a prefix controller definition.
///
/// @section UserManualActionsReqRes Requests and Responses
///////////////////////////////////////////////////////////
///
/// The controller must define handler functions which take a request object and
/// fill the response object.
///
/// A very simple example is the function @LIT{echoRequest} defined in
/// the module @LIT{org/arangodb/actions}.
///
/// @code
/// function (req, res, options, next) {
/// var result;
///
/// result = { request: req, options: options };
///
/// res.responseCode = exports.HTTP_OK;
/// res.contentType = "application/json";
/// res.body = JSON.stringify(result);
/// }
/// @endcode
///
/// Install it as
///
/// @code
/// arangosh> db._routing.save({
/// ........> url: "/echo",
/// ........> action: { controller: "org/arangodb/actions", do: "echoRequest" } });
/// @endcode
///
/// Reload the routing and check
///
/// @LIT{http://127.0.0.1:8529/hello/echo}
///
/// You should see something like
///
/// @code
/// {
/// "request": {
/// "prefix": "/hello/echo",
/// "suffix": [
/// "hello",
/// "echo"
/// ],
/// "path": "/hello/echo",
/// "headers": {
/// "accept-encoding": "gzip, deflate",
/// "accept-language": "de-de,de;q=0.8,en-us;q=0.5,en;q=0.3",
/// "connection": "keep-alive",
/// "content-length": "0",
/// "host": "localhost:8529",
/// "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0"
/// },
/// "requestType": "GET",
/// "parameters": { }
/// },
/// "options": { }
/// }
/// @endcode
///
/// You may also pass options to the called function:
///
/// @code
/// arangosh> db._routing.save({
/// ........> url: "/echo",
/// ........> action: {
/// ........> controller: "org/arangodb/actions",
/// ........> do: "echoRequest",
/// ........> options: { "Hallo": "World" } } });
/// @endcode
///
/// You should now see the options in the result.
///
/// @code
/// {
/// "request": {
/// ...
/// },
/// "options": {
/// "Hallo": "world"
/// }
/// }
/// @endcode
///
/// @section UserManualActionsModify Modifying Request and Response
///
/// As we've seen in the previous examples, actions get called
/// with the request and response objects (named @LIT{req} and @LIT{res} in the
/// examples) passed as parameters to their handler functions.
///
/// The @LIT{req} object contains the incoming HTTP request, which
/// might or might not have been modified by a previous action (if actions were
/// chained).
///
/// A handler can modify the request object in place if desired. This might
/// be useful when writing middleware (see below) that is used to intercept
/// incoming requests, modify them and pass them to the actual handlers.
///
/// While modifying the request object might not be that relevant for
/// non-middleware actions, modifying the response object definitely is. Modifying
/// the response object is an action's only way to return data to the caller of
/// the action.
///
/// We've already seen how to set the HTTP status code, the content type, and the
/// result body. The @LIT{res} object has the following properties for these:
/// - contentType: MIME type of the body as defined in the HTTP standard (e.g.
/// @LIT{text/html}, @LIT{text/plain}, @LIT{application/json}, ...)
/// - responsecode: the HTTP status code of the response as defined in the HTTP
/// standard. Common values for actions that succeed are @LIT{200} or @LIT{201}.
/// Please refer to the HTTP standard for more information.
/// - body: the actual response data
///
/// To set or modify arbitrary headers of the response object, the @LIT{headers}
/// property can be used. For example, to add a user-defined header to the response,
/// the following code will do:
///
/// @code
/// res.headers = res.headers || { }; // headers might or might not be present
/// res.headers['X-Test'] = 'someValue'; // set header X-Test to "someValue"
/// @endcode
///
/// This will set the additional HTTP header @LIT{X-Test} to value @LIT{someValue}.
/// Other headers can be set as well. Note that ArangoDB might change the case
/// of the header names to lower case when assembling the overall response that
/// is sent to the caller.
///
/// It is not necessary to explicitly set a @LIT{Content-Length} header for the
/// response as ArangoDB will calculate the content length automatically and add
/// this header itself. ArangoDB might also add a @LIT{Connection} header itself
/// to handle HTTP keep-alive.
///
/// ArangoDB also supports automatic transformation of the body data to another
/// format. Currently, the only supported transformations are base64-encoding and
/// base64-decoding. Using the transformations, an action can create a base64
/// encoded body and still let ArangoDB send the non-encoded version, for example:
///
/// @code
/// res.body = 'VGhpcyBpcyBhIHRlc3Q=';
/// res.transformations = res.transformations || [ ]; // initialise
/// res.transformations.push('base64decode'); // will base64 decode the response body
/// @endcode
///
/// When ArangoDB processes the response, it will base64-decode what's in @LIT{res.body}
/// and set the HTTP header @LIT{Content-Encoding: binary}. The opposite can be
/// achieved with the @LIT{base64encode} transformation: ArangoDB will then automatically
/// base64-encode the body and set a @LIT{Content-Encoding: base64} HTTP header.
///
/// @section UserManualActionsHandlers Writing dynamic action handlers
/////////////////////////////////////////////////////////////////////
///
/// To write your own dynamic action handlers, you must put them into modules.
///
/// Modules are a means of organising action handlers and making them loadable
/// under specific names.
///
/// To start, we'll define a simple action handler in a module @LIT{/own/test}:
///
/// @code
/// arangosh> db._modules.save({
/// ........> path: "/own/test",
/// ........> content: "exports.do = function(req, res, options, next) { res.body = 'test'; res.responseCode = 200; res.contentType = 'text/html'; };",
/// ........> autoload: true });
/// @endcode
///
/// This does nothing but register a do action handler in a module @LIT{/own/test}.
/// The action handler is not yet callable, but must be mapped to a route first.
/// To map the action to the route @LIT{/ourtest}, execute the following command:
///
/// @code
/// arangosh> db._routing.save({
/// ........> url: "/ourtest",
/// ........> action: { controller: "/own/test" } });
/// @endcode
///
/// In order to see the module in action, you must either restart the server
/// or call the internal reload function.
///
/// @code
/// arangosh> require("internal").reloadRouting()
/// @endcode
///
/// Now use the browser and access
///
/// @LIT{http://localhost:8529/ourtest}
///
/// You will see that the module's do function has been executed.
///
/// @section UserManualActionsAdvanced Advanced Usages
//////////////////////////////////////////////////////
///
/// For detailed information see the reference manual.
///
/// @subsection UserManualActionsAdvancedRedirects Redirects
///
/// Use the following for a permanent redirect:
///
/// @code
/// arangosh> db._routing.save({
/// ........> url: "/",
/// ........> action: {
/// ........> controller: "org/arangodb/actions",
/// ........> do: "redirectRequest",
/// ........> options: {
/// ........> permanently: true,
/// ........> destination: "http://somewhere.else/" } } });
/// @endcode
///
/// @subsection UserManualActionsAdvancedBundles Routing Bundles
///
/// Instead of adding all routes for package separately, you can
/// specify a bundle.
///
/// @code
/// {
/// routes: [
/// { url: "/url1", content: "..." },
/// { url: "/url2", content: "..." },
/// { url: "/url3", content: "..." },
/// ...
/// ]
/// }
/// @endcode
///
/// The advantage is, that you can put all your routes into one document
/// and use a common prefix.
///
/// @code
/// {
/// urlPrefix: "/test",
///
/// routes: [
/// { url: "/url1", content: "..." },
/// { url: "/url2", content: "..." },
/// { url: "/url3", content: "..." },
/// ...
/// ]
/// }
/// @endcode
///
/// will define the URL @LIT{/test/url1}, @LIT{/test/url2}, and
/// @LIT{/test/url3}.
///
/// @subsection UserManualActionsAdvancedMiddleware Writing Middleware
///
/// Assume, you want to log every request. In this case you can easily define
/// an action for the whole url-space @LIT{/}. This action simply logs
/// the requests, calls the next in line, and logs the response.
///
/// @code
/// exports.logRequest = function (req, res, options, next) {
/// console.log("received request: %s", JSON.stringify(req));
/// next();
/// console.log("produced response: %s", JSON.stringify(res));
/// };
/// @endcode
///
/// This function is available as @LIT{org/arangodb/actions/logRequest}.
/// You need to tell ArangoDB that it is should use a prefix match and
/// that the shortest match should win in this case:
///
/// @code
/// arangosh> db._routing.save({
/// ........> middleware: [
/// ........> { url: { match: "/*" }, action: { controller: "org/arangodb/actions", do: "logRequest" } }
/// ........> ]
/// ........> });
/// @endcode
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: c++
// mode: outline-minor
// outline-regexp: "\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @section\\|/// @subsection\\|/// @\\}\\)"
// End: