ArangoDB v3.4 reached End of Life (EOL) and is no longer supported.

This documentation is outdated. Please see the most recent version here: Latest Docs

A Hello World Example for JSON

If you change the example slightly, then a JSON object will be delivered.

arangosh> db._routing.save({ 
........>  url: "/hello/json", 
........>  content: { 
........>  contentType: "application/json", 
........>    body: '{"hello" : "world"}'
........>  }
........> });
arangosh> require("internal").reloadRouting()
Show execution results
Hide execution results
{ 
  "_id" : "_routing/68289", 
  "_key" : "68289", 
  "_rev" : "_bHcRDwu---" 
}

Again check with your browser or cURL 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 contentType to “text/plain” for the example. This makes it easier to check the example using a browser. Or use curl to access the server.


    
Show execution results
Hide execution results
shell> curl --header 'accept: application/json' --dump - http://localhost:8529/hello/json

HTTP/1.1 OK
content-type: application/json; charset=utf-8
x-content-type-options: nosniff

{ 
  "hello" : "world" 
}

    
Show execution results
Hide execution results

    

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.

Static Content

You can specify a body and a content-type.

arangosh> db._routing.save({
........>  url: "/hello/contentType",
........>  content: {
........>    contentType: "text/html",
........>    body: "<html><body>Hello World</body></html>"
........>  }
........> });
arangosh> require("internal").reloadRouting()
Show execution results
Hide execution results
{ 
  "_id" : "_routing/68299", 
  "_key" : "68299", 
  "_rev" : "_bHcRDzi---" 
}

    
Show execution results
Hide execution results
shell> curl --header 'accept: application/json' --dump - http://localhost:8529/hello/contentType

HTTP/1.1 OK
content-type: text/html
x-content-type-options: nosniff

"Hello World"

    
Show execution results
Hide execution results

    

If the content type is text/plain then you can use the short-cut

{ 
  content: "Hello World" 
}

A Simple Action

The simplest dynamic action is:

{ 
  action: { 
    do: "@arangodb/actions/echoRequest" 
  } 
}

It is not advisable to store functions directly in the routing table. It is better to call functions defined in modules. In the above example the function can be accessed from JavaScript as:

require("@arangodb/actions").echoRequest

The function echoRequest is pre-defined. It takes the request objects and echos it in the response.

The signature of such a function must be

function (req, res, options, next)

Examples

arangosh> db._routing.save({ 
........>    url: "/hello/echo",
........>    action: { 
........>    do: "@arangodb/actions/echoRequest" 
........>  } 
........> });
Show execution results
Hide execution results
{ 
  "_id" : "_routing/68309", 
  "_key" : "68309", 
  "_rev" : "_bHcRD2m---" 
}

Reload the routing and check http:// 127.0.0.1:8529/hello/echo

You should see something like

arangosh> arango.GET_RAW("/hello/echo", { "accept" : "application/json" })
Show execution results
Hide execution results
{ 
  "code" : 200, 
  "error" : false, 
  "body" : "{\"request\":{\"authorized\":true,\"user\":\"root\",\"database\":\"_system\",\"url\":\"/hello/echo\",\"protocol\":\"http\",\"server\":{\"address\":\"127.0.0.1\",\"port\":64681},\"client\":{\"address\":\"127.0.0.1\",\"port\":46562,\"id\":\"160027081113943\"},\"internals\":{},\"headers\":{\"host\":\"127....", 
  "headers" : { 
    "connection" : "Keep-Alive", 
    "content-length" : "467", 
    "content-type" : "application/json; charset=utf-8", 
    "http/1.1" : "OK", 
    "server" : "ArangoDB", 
    "x-content-type-options" : "nosniff" 
  } 
}

    
Show execution results
Hide execution results

    

The request might contain path, prefix, suffix, and urlParameters attributes. 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 prefix and the remaining URL parts are stored as an array in suffix. If one or more parameters were matched, then the parameter values are stored in urlParameters.

For example, if the url description is

{ 
  url: { 
    match: "/hello/:name/:action" 
  } 
}

and you request the path /hello/emil/jump, then the request object will contain the following attribute

urlParameters: { 
  name: "emil", 
  action: "jump" 
} 

Action Controller

As an alternative to the simple action, you can use controllers. A controller is a module, defines the function get, put, post, delete, head, patch. If a request of the corresponding type is matched, the function will be called.

Examples

arangosh> db._routing.save({ 
........>  url: "/hello/echo",
........>  action: { 
........>    controller: "@arangodb/actions/echoController" 
........>  } 
........> });
Show execution results
Hide execution results
{ 
  "_id" : "_routing/68319", 
  "_key" : "68319", 
  "_rev" : "_bHcRD42---" 
}

Reload the routing and check http:// 127.0.0.1:8529/hello/echo:

arangosh> arango.GET_RAW("/hello/echo", { "accept" : "application/json" })
Show execution results
Hide execution results
{ 
  "code" : 200, 
  "error" : false, 
  "body" : "{\"request\":{\"authorized\":true,\"user\":\"root\",\"database\":\"_system\",\"url\":\"/hello/echo\",\"protocol\":\"http\",\"server\":{\"address\":\"127.0.0.1\",\"port\":64681},\"client\":{\"address\":\"127.0.0.1\",\"port\":46562,\"id\":\"160027081113943\"},\"internals\":{},\"headers\":{\"host\":\"127....", 
  "headers" : { 
    "connection" : "Keep-Alive", 
    "content-length" : "467", 
    "content-type" : "application/json; charset=utf-8", 
    "http/1.1" : "OK", 
    "server" : "ArangoDB", 
    "x-content-type-options" : "nosniff" 
  } 
}

    
Show execution results
Hide execution results

    

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

{ 
  url: { 
    match: /hello/*" 
  } 
}

You can use

{ 
  action: { 
    prefixController: "@arangodb/actions" 
  } 
}

to define a prefix controller. If the URL /hello/echoController is given, then the module @arangodb/actions/echoController is used.

If you use a prefix controller, you should make certain that no unwanted actions are available under the prefix.

The definition

{ 
  action: "@arangodb/actions" 
}

is a short-cut for a prefix controller definition.

Function Action

You can also store a function directly in the routing table.

Examples

arangosh> db._routing.save({ 
........>  url: "/hello/echo",
........>  action: { 
........>    callback: "function(req,res) {res.statusCode=200; res.body='Hello'}" 
........>  } 
........> });
Show execution results
Hide execution results
{ 
  "_id" : "_routing/68329", 
  "_key" : "68329", 
  "_rev" : "_bHcRD7S---" 
}
arangosh> arango.GET_RAW("hello/echo", { "accept" : "application/json" })
arangosh> db._query("FOR route IN _routing FILTER route.url == '/hello/echo' REMOVE route in _routing")
arangosh> require("internal").reloadRouting()
Show execution results
Hide execution results
{ 
  "code" : 200, 
  "error" : false, 
  "body" : "Hello", 
  "headers" : { 
    "connection" : "Keep-Alive", 
    "content-length" : "5", 
    "content-type" : "application/json; charset=utf-8", 
    "http/1.1" : "OK", 
    "server" : "ArangoDB", 
    "x-content-type-options" : "nosniff" 
  } 
}
[object ArangoQueryCursor, count: 0, cached: false, hasMore: false]

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 echoRequest defined in the module @arangodb/actions.

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);
}

Install it via:

arangosh> db._routing.save({ 
........>  url: "/echo",
........>  action: { 
........>    do: "@arangodb/actions/echoRequest" 
........>  }
........> })
Show execution results
Hide execution results
{ 
  "_id" : "_routing/68338", 
  "_key" : "68338", 
  "_rev" : "_bHcRE-----" 
}

Reload the routing and check http:// 127.0.0.1:8529/hello/echo

You should see something like

arangosh> arango.GET_RAW("/hello/echo", { "accept" : "application/json" })
arangosh> db._query("FOR route IN _routing FILTER route.url == '/hello/echo' REMOVE route in _routing")
arangosh> require("internal").reloadRouting()
Show execution results
Hide execution results
{ 
  "code" : 404, 
  "error" : true, 
  "errorNum" : 404, 
  "errorMessage" : "404 Not Found", 
  "body" : "{\"error\":true,\"code\":404,\"errorNum\":404,\"errorMessage\":\"unknown path '/hello/echo'\"}", 
  "headers" : { 
    "connection" : "Keep-Alive", 
    "content-length" : "84", 
    "content-type" : "application/json; charset=utf-8", 
    "http/1.1" : "Not Found", 
    "server" : "ArangoDB", 
    "x-content-type-options" : "nosniff" 
  } 
}
[object ArangoQueryCursor, count: 0, cached: false, hasMore: false]

You may also pass options to the called function:

arangosh> db._routing.save({ 
........>  url: "/echo",
........>  action: {
........>    do: "@arangodb/actions/echoRequest",
........>    options: { 
........>      "Hello": "World" 
........>    }
........>  } 
........> });
Show execution results
Hide execution results
{ 
  "_id" : "_routing/68347", 
  "_key" : "68347", 
  "_rev" : "_bHcREAm---" 
}

You now see the options in the result:

arangosh> arango.GET_RAW("/echo", { accept: "application/json" })
arangosh> db._query("FOR route IN _routing FILTER route.url == '/echo' REMOVE route in _routing")
arangosh> require("internal").reloadRouting()
Show execution results
Hide execution results
{ 
  "code" : 200, 
  "error" : false, 
  "body" : "{\"request\":{\"authorized\":true,\"user\":\"root\",\"database\":\"_system\",\"url\":\"/echo\",\"protocol\":\"http\",\"server\":{\"address\":\"127.0.0.1\",\"port\":64681},\"client\":{\"address\":\"127.0.0.1\",\"port\":46562,\"id\":\"160027081113943\"},\"internals\":{},\"headers\":{\"host\":\"127.0.0.1\"...", 
  "headers" : { 
    "connection" : "Keep-Alive", 
    "content-length" : "461", 
    "content-type" : "application/json; charset=utf-8", 
    "http/1.1" : "OK", 
    "server" : "ArangoDB", 
    "x-content-type-options" : "nosniff" 
  } 
}
[object ArangoQueryCursor, count: 0, cached: false, hasMore: false]