mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/arangodb/arangodb into devel
This commit is contained in:
commit
f7ece88b35
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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<string>` (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
|
||||
|
|
|
@ -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
|
||||
router.get(/* ... */)
|
||||
.queryParam('num', joi.number().required());
|
||||
```
|
||||
|
||||
!SECTION body
|
||||
|
||||
`endpoint.body([model], [mimes], [description]): this`
|
||||
|
||||
TODO
|
||||
|
||||
**Arguments**
|
||||
|
||||
* **model**: `Model | Schema` (optional)
|
||||
|
||||
TODO
|
||||
|
||||
* **mimes**: `Array<string>` (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](https://github.com/jshttp/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<string>` (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](https://github.com/jshttp/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();
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<Transport>`
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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*.
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -93,10 +93,10 @@
|
|||
%>
|
||||
<input type="hidden" id="<%=row.id%>" value="<%=row.value||''%>" placeholder="<%=row.placeholder||''%>"></input>
|
||||
<% if (row.addAdd) {%>
|
||||
<button id="<%='addAfter_' + row.id%>" class="graphViewer-icon-button gv-icon-small add"></button>
|
||||
<button id="<%='addAfter_' + row.id%>" class="graphViewer-icon-button gv-icon-small add addAfter"></button>
|
||||
<% } %>
|
||||
<% if (row.addDelete) {%>
|
||||
<button id="<%='remove_' + row.id%>" class="graphViewer-icon-button gv_internal_remove_line gv-icon-small delete"></button>
|
||||
<button id="<%='remove_' + row.id%>" class="graphViewer-icon-button gv_internal_remove_line gv-icon-small delete addDelete"></button>
|
||||
<% } %>
|
||||
<%
|
||||
break;
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
<li><a target="_blank" href="https://docs.arangodb.com/3.0/Manual/Foxx/Anatomy.html">Foxx Anatomy</a></li>
|
||||
<li><a target="_blank" href="https://docs.arangodb.com/3.0/Manual/Foxx/GettingStarted.html">Writing Your First Microservice</a></li>
|
||||
<li><a target="_blank" href="https://docs.arangodb.com/3.0/Manual/Foxx/LegacyMode.html">Legacy mode for 2.8 services </a></li>
|
||||
<li><a target="_blank" href="https://docs.arangodb.com/3.0/Foxx/index.html">Go to Foxx startpage</a></li>
|
||||
<li><a target="_blank" href="https://docs.arangodb.com/3.0/Manual/Foxx/index.html">Go to Foxx startpage</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@
|
|||
tr {
|
||||
|
||||
&.spacer {
|
||||
height: 10px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
&.first {
|
||||
|
|
|
@ -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}}}}}}]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue