mirror of https://gitee.com/bigwinds/arangodb
896 lines
26 KiB
Plaintext
896 lines
26 KiB
Plaintext
!CHAPTER Migrating 2.x services to 3.0
|
|
|
|
When migrating services from older versions of ArangoDB it is generally recommended you make sure they work in [legacy compatibility mode](LegacyMode.md), which can also serve as a stop-gap solution.
|
|
|
|
This chapter outlines the major differences in the Foxx API between ArangoDB 2.8 and ArangoDB 3.0.
|
|
|
|
!SECTION Migrating from pre-2.8
|
|
|
|
When migrating from a version older than ArangoDB 2.8 please note that starting with ArangoDB 2.8 the behaviour of the `require` function more closely mimics the behaviour observed in Node.js and module bundlers for browsers, e.g.:
|
|
|
|
In a file `/routes/examples.js` (relative to the root folder of the service):
|
|
|
|
* `require('./my-module')` will be attempted to be resolved in the following order:
|
|
|
|
1. `/routes/my-module` (relative to service root)
|
|
2. `/routes/my-module.js` (relative to service root)
|
|
3. `/routes/my-module.json` (relative to service root)
|
|
4. `/routes/my-module/index.js` (relative to service root)
|
|
5. `/routes/my-module/index.json` (relative to service root)
|
|
|
|
* `require('lodash')` will be attempted to be resolved in the following order:
|
|
|
|
1. `/routes/node_modules/lodash` (relative to service root)
|
|
2. `/node_modules/lodash` (relative to service root)
|
|
3. ArangoDB module `lodash`
|
|
4. Node compatibility module `lodash`
|
|
5. Bundled NPM module `lodash`
|
|
|
|
* `require('/abs/path')` will be attempted to be resolved in the following order:
|
|
|
|
1. `/abs/path` (relative to file system root)
|
|
2. `/abs/path.js` (relative to file system root)
|
|
3. `/abs/path.json` (relative to file system root)
|
|
4. `/abs/path/index.js` (relative to file system root)
|
|
5. `/abs/path/index.json` (relative to file system root)
|
|
|
|
This behaviour is incompatible with the source code generated by the Foxx generator in the web interface before ArangoDB 2.8.
|
|
|
|
**Note:** The `org/arangodb` module is aliased to the new name `@arangodb` in ArangoDB 3.0.0 and the `@arangodb` module was aliased to the old name `org/arangodb` in ArangoDB 2.8.0. Either one will work in 2.8 and 3.0 but outside of legacy services you should use `@arangodb` going forward.
|
|
|
|
!SUBSECTION Foxx queue
|
|
|
|
In ArangoDB 2.6 Foxx introduced a new way to define queued jobs using Foxx scripts to replace the function-based job type definitions which were causing problems when restarting the server. The function-based jobs have been removed in 2.7 and are no longer supported at all.
|
|
|
|
!SUBSECTION CoffeeScript
|
|
|
|
ArangoDB 3.0 no longer provides built-in support for CoffeeScript source files, even in legacy compatibility mode. If you want to use an alternative language like CoffeeScript, make sure to pre-compile the raw source files to JavaScript and use the compiled JavaScript files in the service.
|
|
|
|
!SUBSECTION The request module
|
|
|
|
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 compatibility 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.
|
|
|
|
!SUBSECTION Bundled NPM modules
|
|
|
|
The bundled NPM modules have been upgraded and may include backwards-incompatible changes, especially the API of `joi` has changed several times. If in doubt you should bundle your own versions of these modules to ensure specific versions will be used.
|
|
|
|
The utility module `lodash` is now available and should be used instead of `underscore`, but both modules will continue to be provided.
|
|
|
|
!SECTION Manifest
|
|
|
|
Many of the fields that were required in ArangoDB 2.x are now optional and can be safely omitted.
|
|
|
|
To avoid compatibility problems with future versions of ArangoDB you should always specify the `engines` field, e.g.:
|
|
|
|
```json
|
|
{
|
|
"engines": {
|
|
"arangodb": "^3.0.0"
|
|
}
|
|
}
|
|
```
|
|
|
|
!SUBSECTION Controllers & exports
|
|
|
|
Previously Foxx distinguished between `exports` and `controllers`, each of which could be specified as an object. In ArangoDB 3.0 these have been merged into a single `main` field specifying an entry file.
|
|
|
|
The easiest way to migrate services using multiple exports and/or controllers is to create a separate entry file that imports these files:
|
|
|
|
Old (manifest.json):
|
|
|
|
```json
|
|
{
|
|
"exports": {
|
|
"doodads": "doodads.js",
|
|
"dingbats": "dingbats.js"
|
|
},
|
|
"controllers": {
|
|
"/doodads": "routes/doodads.js",
|
|
"/dingbats": "routes/dingbats.js",
|
|
"/": "routes/root.js"
|
|
}
|
|
}
|
|
```
|
|
|
|
New (manifest.json):
|
|
|
|
```json
|
|
{
|
|
"main": "index.js"
|
|
}
|
|
```
|
|
|
|
New (index.js):
|
|
|
|
```js
|
|
'use strict';
|
|
module.context.use('/doodads', require('./routes/doodads'));
|
|
module.context.use('/dingbats', require('./routes/dingbats'));
|
|
module.context.use('/', require('./routes/root'));
|
|
module.exports = {
|
|
doodads: require('./doodads'),
|
|
dingbats: require('./dingbats')
|
|
};
|
|
```
|
|
|
|
!SUBSECTION Index redirect
|
|
|
|
If you previously did not define the `defaultDocument` field, please note that in ArangoDB 3.0 the field will no longer default to the value `index.html` when omitted:
|
|
|
|
Old:
|
|
|
|
```json
|
|
{
|
|
// no defaultDocument
|
|
}
|
|
```
|
|
|
|
New:
|
|
|
|
```json
|
|
{
|
|
"defaultDocument": "index.html"
|
|
}
|
|
```
|
|
|
|
This also means it is no longer necessary to specify the `defaultDocument` field with an empty value to prevent the redirect and be able to serve requests at the `/` (root) path of the mount point:
|
|
|
|
Old:
|
|
|
|
```json
|
|
{
|
|
"defaultDocument": ""
|
|
}
|
|
```
|
|
|
|
New:
|
|
|
|
```json
|
|
{
|
|
// no defaultDocument
|
|
}
|
|
```
|
|
|
|
!SUBSECTION Assets
|
|
|
|
The `assets` field is no longer supported in ArangoDB 3.0 outside of legacy compatibility mode.
|
|
|
|
If you previously used the field to serve individual files as-is you can simply use the `files` field instead:
|
|
|
|
Old:
|
|
|
|
```json
|
|
{
|
|
"assets": {
|
|
"client.js": {
|
|
"files": ["assets/client.js"],
|
|
"contentType": "application/javascript"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
New:
|
|
|
|
```json
|
|
{
|
|
"files": {
|
|
"client.js": {
|
|
"path": "assets/client.js",
|
|
"type": "application/javascript"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
If you relied on being able to specify multiple files that should be concatenated, you will have to use build tools outside of ArangoDB to prepare these files accordingly.
|
|
|
|
!SUBSECTION Root element
|
|
|
|
The `rootElement` field is no longer supported and has been removed entirely.
|
|
|
|
If your controllers relied on this field being available you need to adjust your schemas and routes to be able to handle the full JSON structure of incoming documents.
|
|
|
|
!SUBSECTION System services
|
|
|
|
The `isSystem` field is no longer supported. The presence or absence of the field had no effect in most recent versions of ArangoDB 2.x and has now been removed entirely.
|
|
|
|
!SECTION The application context
|
|
|
|
The global `applicationContext` variable available in Foxx modules has been replaced with the `context` attribute of the `module` variable. For consistency it is now referred to as the *service* context throughout this documentation.
|
|
|
|
Some methods of the service context have changed in ArangoDB 3.0:
|
|
|
|
* `fileName()` now behaves like `path()` did in ArangoDB 2.x
|
|
* `path()` has been removed (use `fileName()` instead)
|
|
* `foxxFileName()` has been removed (use `fileName()` instead)
|
|
|
|
Additionally the `version` and `name` attributes have been removed and can now only be accessed via the `manifest` attribute (as `manifest.version` and `manifest.name`). Note that the corresponding manifest fields are now optional and may be omitted.
|
|
|
|
The `options` attribute has also been removed as it should be considered an implementation detail. You should instead access the `dependencies` and `configuration` attributes directly.
|
|
|
|
The internal `_prefix` attribute (which was an alias for `basePath`) and the internal `comment` and `clearComments` methods (which were used by the magical documentation comments in ArangoDB 2.x) have also been removed.
|
|
|
|
The internal `_service` attribute (which provides access to the service itself) has been renamed to `service`.
|
|
|
|
!SECTION Repositories and models
|
|
|
|
Previously Foxx was heavily built around the concept of repositories and models, which provided complex but rarely necessary abstractions on top of ArangoDB collections and documents. In ArangoDB 3.0 these have been removed entirely.
|
|
|
|
!SUBSECTION Repositories vs collections
|
|
|
|
Repositories mostly wrapped methods that already existed on ArangoDB collection objects and primarily dealt with converting between plain ArangoDB documents and Foxx model instances. In ArangoDB 3.0 you can simply use these collections directly and treat documents as plain JavaScript objects.
|
|
|
|
Old:
|
|
|
|
```js
|
|
'use strict';
|
|
const Foxx = require('org/arangodb/foxx');
|
|
const myRepo = new Foxx.Repository(
|
|
applicationContext.collection('myCollection'),
|
|
{model: Foxx.Model}
|
|
);
|
|
|
|
// ...
|
|
|
|
const models = myRepo.byExample({color: 'green'});
|
|
res.json(models.map(function (model) {
|
|
return model.forClient();
|
|
}));
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
'use strict';
|
|
const myDocs = module.context.collection('myCollection');
|
|
|
|
// ...
|
|
|
|
const docs = myDocs.byExample({color: 'green'});
|
|
res.json(docs);
|
|
```
|
|
|
|
!SUBSECTION Schema validation
|
|
|
|
The main purpose of models in ArangoDB 2.x was to validate incoming data using joi schemas. In more recent versions of ArangoDB 2.x it was already possible to pass these schemas directly in most places where a model was expected as an argument. The only difference is that schemas should now be considered the default.
|
|
|
|
If you previously relied on the automatic validation of Foxx model instances when setting attributes or instantiating models from untrusted data, you can simply use the schema's `validate` method directly.
|
|
|
|
Old:
|
|
|
|
```js
|
|
'use strict';
|
|
const joi = require('joi');
|
|
const mySchema = {
|
|
name: joi.string().required(),
|
|
size: joi.number().required()
|
|
};
|
|
const Foxx = require('org/arangodb/foxx');
|
|
const MyModel = Foxx.Model.extend({schema: mySchema});
|
|
|
|
// ...
|
|
|
|
const model = new MyModel(req.json());
|
|
if (!model.isValid) {
|
|
res.status(400);
|
|
res.write('Bad request');
|
|
return;
|
|
}
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
'use strict';
|
|
const joi = require('joi');
|
|
// Note this is now wrapped in a joi.object()
|
|
const mySchema = joi.object({
|
|
name: joi.string().required(),
|
|
size: joi.number().required()
|
|
}).required();
|
|
|
|
// ...
|
|
|
|
const result = mySchema.validate(req.body);
|
|
if (result.errors) {
|
|
res.status(400);
|
|
res.write('Bad request');
|
|
return;
|
|
}
|
|
```
|
|
|
|
!SUBSECTION Migrating models
|
|
|
|
While most use cases for models can now be replaced with plain joi schemas, there is still the concept of a "model" in Foxx in ArangoDB 3.0 although it is quite different from Foxx models in ArangoDB 2.x.
|
|
|
|
A model in Foxx now refers to a plain JavaScript object with an optional `schema` attribute and the optional methods `forClient` and `fromClient`. Models can be used instead of plain joi schemas to define request and response bodies but there are no model "instances" in ArangoDB 3.0.
|
|
|
|
Old:
|
|
|
|
```js
|
|
'use strict';
|
|
const _ = require('underscore');
|
|
const joi = require('joi');
|
|
const Foxx = require('org/arangodb/foxx');
|
|
const MyModel = Foxx.Model.extend({
|
|
schema: {
|
|
name: joi.string().required(),
|
|
size: joi.number().required()
|
|
},
|
|
forClient () {
|
|
return _.omit(this.attributes, ['_key', '_id', '_rev']);
|
|
}
|
|
});
|
|
|
|
// ...
|
|
|
|
ctrl.get(/* ... */)
|
|
.bodyParam('body', {type: MyModel});
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
'use strict';
|
|
const _ = require('lodash');
|
|
const joi = require('joi');
|
|
const MyModel = {
|
|
schema: joi.object({
|
|
name: joi.string().required(),
|
|
size: joi.number().required()
|
|
}).required(),
|
|
forClient (data) {
|
|
return _.omit(data, ['_key', '_id', '_rev']);
|
|
}
|
|
};
|
|
|
|
// ...
|
|
|
|
router.get(/* ... */)
|
|
.body(MyModel);
|
|
```
|
|
|
|
!SUBSECTION Triggers
|
|
|
|
When saving, updating, replacing or deleting models in ArangoDB 2.x using the repository methods the repository and model would fire events that could be subscribed to in order to perform side-effects.
|
|
|
|
Note that even in 2.x these events would not fire when using queries or manipulating documents in any other way than using the specific repository methods that operated on individual documents.
|
|
|
|
This behaviour is no longer available in ArangoDB 3.0 but can be emulated by using an `EventEmitter` directly if it is not possible to solve the problem differently:
|
|
|
|
Old:
|
|
|
|
```js
|
|
'use strict';
|
|
const Foxx = require('org/arangodb/foxx');
|
|
const MyModel = Foxx.Model.extend({
|
|
// ...
|
|
}, {
|
|
afterRemove () {
|
|
console.log(this.get('name'), 'was removed');
|
|
}
|
|
});
|
|
|
|
// ...
|
|
|
|
const model = myRepo.firstExample({name: 'myName'});
|
|
myRepo.remove(model);
|
|
// -> "myName was removed successfully"
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
'use strict';
|
|
const EventEmitter = require('events');
|
|
const emitter = new EventEmitter();
|
|
emitter.on('afterRemove', function (doc) {
|
|
console.log(doc.name, 'was removed');
|
|
});
|
|
|
|
// ...
|
|
|
|
const doc = myDocs.firstExample({name: 'myName'});
|
|
myDocs.remove(doc);
|
|
emitter.emit('afterRemove', doc);
|
|
// -> "myName was removed successfully"
|
|
```
|
|
|
|
Or simply:
|
|
|
|
```js
|
|
'use strict';
|
|
function afterRemove(doc) {
|
|
console.log(doc.name, 'was removed');
|
|
}
|
|
|
|
// ...
|
|
|
|
const doc = myDocs.firstExample({name: 'myName'});
|
|
myDocs.remove(doc);
|
|
afterRemove(doc);
|
|
// -> "myName was removed successfully"
|
|
```
|
|
|
|
!SECTION Controllers vs routers
|
|
|
|
Foxx Controllers have been replaced with [routers](Router/README.md). This is more than a cosmetic change as there are significant differences in behaviour:
|
|
|
|
Controllers were automatically mounted when the file defining them was executed. Routers need to be explicitly mounted using the `module.context.use` method. Routers can also be exported, imported and even nested. This makes it easier to split up complex routing trees across multiple files.
|
|
|
|
Old:
|
|
|
|
```js
|
|
'use strict';
|
|
const Foxx = require('org/arangodb/foxx');
|
|
const ctrl = new Foxx.Controller(applicationContext);
|
|
|
|
ctrl.get('/hello', function (req, res) {
|
|
// ...
|
|
});
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
'use strict';
|
|
const createRouter = require('org/arangodb/foxx/router');
|
|
const router = createRouter();
|
|
// If you are importing this file from your entry file ("main"):
|
|
module.exports = router;
|
|
// Otherwise: module.context.use(router);
|
|
|
|
router.get('/hello', function (req, res) {
|
|
// ...
|
|
});
|
|
```
|
|
|
|
Some general changes in behaviour that might trip you up:
|
|
|
|
* When specifying path parameters with schemas Foxx will now ignore the route if the schema does not match (i.e. `/hello/foxx` will no longer match `/hello/:num` if `num` specifies a schema that doesn't match the value `"foxx"`). With controllers this could previously result in users seeing a 400 (bad request) error when they should instead be served a 404 (not found) response.
|
|
|
|
* When a request is made with an HTTP verb not supported by an endpoint, Foxx will now respond with a 405 (method not allowed) error with an appropriate `Allowed` header listing the supported HTTP verbs for that endpoint.
|
|
|
|
* Foxx will no longer parse your JSDoc comments to generate route documentation (use the `summary` and `description` methods of the endpoint instead).
|
|
|
|
* The `apiDocumentation` method now lives on the service context and behaves slightly differently.
|
|
|
|
* There is no router equivalent for the `activateAuthentication` and `activateSessions` methods. Instead you should use the session middleware (see the section on sessions below).
|
|
|
|
* There is no `del` alias for the `delete` method on routers. It has always been safe to use keywords as method names in Foxx, so the use of this alias was already discouraged before.
|
|
|
|
* The `allRoutes` proxy is no lot available on routers but can easily be replaced with middleware or child routers.
|
|
|
|
!SUBSECTION Before, after and around
|
|
|
|
The `before`, `after` and `around` methods can easily be replaced by middleware:
|
|
|
|
Old:
|
|
|
|
```js
|
|
let start;
|
|
ctrl.before(function (req, res) {
|
|
start = Date.now();
|
|
});
|
|
ctrl.after(function (req, res) {
|
|
console.log('Request handled in ', (Date.now() - start), 'ms');
|
|
});
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
router.use(function (req, res, next) {
|
|
let start = Date.now();
|
|
next();
|
|
console.log('Request handled in ', (Date.now() - start), 'ms');
|
|
});
|
|
```
|
|
|
|
Note that unlike `around` middleware receives the `next` function as the *third* argument (the "opts" argument has no equivalent).
|
|
|
|
!SUBSECTION The request context
|
|
|
|
When defining a route on a controller the controller would return an object called *request context*. Routers return a similar object called *endpoint*. Routers also return endpoints when mounting child routers or middleware, as does the `use` method of the service context.
|
|
|
|
The main differences between the new endpoints and the objects returned by controllers in previous versions of ArangoDB are:
|
|
|
|
* `bodyParam` is now simply called `body`; it is no longer neccessary or possible to give the body a name and the request body will not show up in the request parameters. It's also possible to specify a MIME type
|
|
|
|
* `body`, `queryParam` and `pathParam` now take position arguments instead of an object. For specifics see the [endpoint documentation](Router/Endpoints.md).
|
|
|
|
* `notes` is now called `description` and takes a single string argument.
|
|
|
|
* `onlyIf` and `onlyIfAuthenticated` are no longer available; they can be emulated with middleware if necessary:
|
|
|
|
Old:
|
|
|
|
```js
|
|
ctrl.get(/* ... */)
|
|
.onlyIf(function (req) {
|
|
if (!req.user) {
|
|
throw new Error('Not authenticated!');
|
|
}
|
|
});
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
router.use(function (req, res, next) {
|
|
if (!req.arangoUser) {
|
|
res.throw(403, 'Not authenticated!');
|
|
}
|
|
next();
|
|
});
|
|
|
|
router.get(/* ... */);
|
|
```
|
|
|
|
!SUBSECTION Error handling
|
|
|
|
The `errorResponse` method provided by controller request contexts has no equivalent in router endpoints. If you want to handle specific error types with specific status codes you need to catch them explicitly, either in the route or in a middleware:
|
|
|
|
Old:
|
|
|
|
```js
|
|
ctrl.get('/puppies', function (req, res) {
|
|
// Exception is thrown here
|
|
})
|
|
.errorResponse(TooManyPuppiesError, 400, 'Something went wrong!');
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
ctrl.get('/puppies', function (req, res) {
|
|
try {
|
|
// Exception is thrown here
|
|
} catch (e) {
|
|
if (!(e instanceof TooManyPuppiesError)) {
|
|
throw e;
|
|
}
|
|
res.throw(400, 'Something went wrong!');
|
|
}
|
|
})
|
|
// The "error" method merely documents the meaning
|
|
// of the status code and has no other effect.
|
|
.error(400, 'Thrown if there are too many puppies.');
|
|
```
|
|
|
|
Note that errors created with `http-errors` are still handled by Foxx intelligently. In fact `res.throw` is just a helper method for creating and throwing these errors.
|
|
|
|
!SUBSECTION Request objects
|
|
|
|
The names of some attributes of the request object have been adjusted to more closely align with those of the corresponding methods on the endpoint objects and established conventions in other JavaScript frameworks:
|
|
|
|
* `req.urlParameters` is now called `req.pathParams`
|
|
|
|
* `req.parameters` is now called `req.queryParams`
|
|
|
|
* `req.params()` is now called `req.param()`
|
|
|
|
* `req.requestType` is now called `req.method`
|
|
|
|
* `req.compatibility` is now called `req.arangoVersion`
|
|
|
|
* `req.user` is now called `req.arangoUser`
|
|
|
|
Some attributes have been removed or changed:
|
|
|
|
* `req.cookies` has been removed entirely (use `req.cookie(name)`)
|
|
|
|
* `req.requestBody` has been removed entirely (see below)
|
|
|
|
* `req.suffix` is now a string rather than an array
|
|
|
|
Additionally the `req.server` and `req.client` attributes are no longer available. The information is now exposed in a way that can (optionally) transparently handle proxy forwarding headers:
|
|
|
|
* `req.hostname` defaults to `req.server.address`
|
|
|
|
* `req.port` defaults to `req.server.port`
|
|
|
|
* `req.remoteAddress` defaults to `client.address`
|
|
|
|
* `req.remotePort` defaults to `client.port`
|
|
|
|
Finally, the `req.cookie` method now takes the `signed` options directly.
|
|
|
|
Old:
|
|
|
|
```js
|
|
const sid = req.cookie('sid', {
|
|
signed: {
|
|
secret: 'keyboardcat',
|
|
algorithm: 'sha256'
|
|
}
|
|
});
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
const sid = req.cookie('sid', {
|
|
secret: 'keyboardcat',
|
|
algorithm: 'sha256'
|
|
});
|
|
```
|
|
|
|
!SUBSUBSECTION Request bodies
|
|
|
|
The `req.body` is no longer a method and no longer automatically parses JSON request bodies unless a request body was defined. The `req.rawBody` now corresponds to the `req.rawBodyBuffer` of ArangoDB 2.x and is also no longer a method.
|
|
|
|
Old:
|
|
|
|
```js
|
|
ctrl.post('/', function (req, res) {
|
|
const data = req.body();
|
|
// ...
|
|
});
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
router.post('/', function (req, res) {
|
|
const data = req.body;
|
|
// ...
|
|
})
|
|
.body(['json']);
|
|
```
|
|
|
|
Or simply:
|
|
|
|
```js
|
|
const joi = require('joi');
|
|
router.post('/', function (req, res) {
|
|
const data = req.body;
|
|
// ...
|
|
})
|
|
.body(joi.object().optional());
|
|
```
|
|
|
|
!SUBSUBSECTION Multipart requests
|
|
|
|
The `req.requestParts` method has been removed entirely. If you need to accept multipart request bodies, you can simply define the request body using a multipart MIME type like `multipart/form-data`:
|
|
|
|
Old:
|
|
|
|
```js
|
|
ctrl.post('/', function (req, res) {
|
|
const parts = req.requestParts();
|
|
// ...
|
|
});
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
router.post('/', function (req, res) {
|
|
const parts = req.body;
|
|
// ...
|
|
})
|
|
.body(['multipart/form-data']);
|
|
```
|
|
|
|
!SUBSECTION Response objects
|
|
|
|
The response object has a lot of new methods in ArangoDB 3.0 but otherwise remains similar to the response object of previous versions:
|
|
|
|
The `res.send` method behaves very differently from how the method with the same name behaved in ArangoDB 2.x: the conversion now takes the response body definition of the route into account. There is a new method `res.write` that implements the old behaviour.
|
|
|
|
Note that consecutive calls to `res.write` will append to the response body rather than replacing it like `res.send`.
|
|
|
|
The `res.contentType` property is also no longer available. If you want to set the MIME type of the response body to an explicit value you should set the `content-type` header instead:
|
|
|
|
Old:
|
|
|
|
```js
|
|
res.contentType = 'application/json';
|
|
res.body = JSON.stringify(results);
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
res.set('content-type', 'application/json');
|
|
res.body = JSON.stringify(results);
|
|
```
|
|
|
|
Or simply:
|
|
|
|
```js
|
|
// sets the content type to JSON
|
|
// if it has not already been set
|
|
res.json(results);
|
|
```
|
|
|
|
The `res.cookie` method now takes the `signed` options as part of the regular options object.
|
|
|
|
Old:
|
|
|
|
```js
|
|
res.cookie('sid', 'abcdef', {
|
|
ttl: 60 * 60,
|
|
signed: {
|
|
secret: 'keyboardcat',
|
|
algorithm: 'sha256'
|
|
}
|
|
});
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
res.cookie('sid', 'abcdef', {
|
|
ttl: 60 * 60,
|
|
secret: 'keyboardcat',
|
|
algorithm: 'sha256'
|
|
});
|
|
```
|
|
|
|
!SUBSECTION Dependency injection
|
|
|
|
There is no equivalent of the `addInjector` method available in ArangoDB 2.x controllers. Most use cases can be solved by simply using plain variables but if you need something more flexible you can also use middleware:
|
|
|
|
Old:
|
|
|
|
```js
|
|
ctrl.addInjector('magicNumber', function () {
|
|
return Math.random();
|
|
});
|
|
|
|
ctrl.get('/', function (req, res, injected) {
|
|
res.json(injected.magicNumber);
|
|
});
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
function magicMiddleware(name) {
|
|
return {
|
|
register () {
|
|
let magic;
|
|
return function (req, res, next) {
|
|
if (!magic) {
|
|
magic = Math.random();
|
|
}
|
|
req[name] = magic;
|
|
next();
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
router.use(magicMiddleware('magicNumber'));
|
|
|
|
router.get('/', function (req, res) {
|
|
res.json(req.magicNumber);
|
|
});
|
|
```
|
|
|
|
Or simply:
|
|
|
|
```js
|
|
const magicNumber = Math.random();
|
|
|
|
router.get('/', function (req, res) {
|
|
res.json(magicNumber);
|
|
});
|
|
```
|
|
|
|
!SECTION Sessions
|
|
|
|
The `ctrl.activateSessions` method and the related `util-sessions-local` Foxx service have been replaced with the [Foxx sessions](Sessions/README.md) middleware. It is no longer possible to use the built-in session storage but you can simply pass in any document collection directly.
|
|
|
|
Old:
|
|
|
|
```js
|
|
const localSessions = applicationContext.dependencies.localSessions;
|
|
const sessionStorage = localSessions.sessionStorage;
|
|
ctrl.activateSessions({
|
|
sessionStorage: sessionStorage,
|
|
cookie: {secret: 'keyboardcat'}
|
|
});
|
|
|
|
ctrl.destroySession('/logout', function (req, res) {
|
|
res.json({message: 'Goodbye!'});
|
|
});
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
const sessionMiddleware = require('@arangodb/foxx/sessions');
|
|
const cookieTransport = require('@arangodb/foxx/sessions/transports/cookie');
|
|
router.use(sessionMiddleware({
|
|
storage: module.context.collection('sessions'),
|
|
transport: cookieTransport('keyboardcat')
|
|
}));
|
|
|
|
router.post('/logout', function (req, res) {
|
|
req.sessionStorage.clear(req.session);
|
|
res.json({message: 'Goodbye!'});
|
|
});
|
|
```
|
|
|
|
!SECTION Auth and OAuth2
|
|
|
|
The `util-simple-auth` and `util-oauth2` Foxx services have been replaced with the [Foxx auth](Auth.md) and [Foxx OAuth2](OAuth2.md) modules. It is no longer necessary to install these services as dependencies in order to use the functionality.
|
|
|
|
Old:
|
|
|
|
```js
|
|
'use strict';
|
|
const auth = applicationContext.dependencies.simpleAuth;
|
|
|
|
// ...
|
|
|
|
const valid = auth.verifyPassword(authData, password);
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
'use strict';
|
|
const createAuth = require('@arangodb/foxx/auth');
|
|
const auth = createAuth(); // Use default configuration
|
|
|
|
// ...
|
|
|
|
const valid = auth.verifyPassword(authData, password);
|
|
```
|
|
|
|
!SECTION Foxx queries
|
|
|
|
The `createQuery` method has been removed. It can be trivially replaced with plain JavaScript functions and direct calls to [the `db._query` method](Modules.md):
|
|
|
|
Old:
|
|
|
|
```js
|
|
'use strict';
|
|
const Foxx = require('org/arangodb/foxx');
|
|
const query = Foxx.createQuery({
|
|
query: 'FOR u IN _users SORT u.user ASC RETURN u[@propName]',
|
|
params: ['propName'],
|
|
transform: function (results, uppercase) {
|
|
return (
|
|
uppercase
|
|
? results[0].toUpperCase()
|
|
: results[0].toLowerCase()
|
|
);
|
|
}
|
|
});
|
|
|
|
query('user', true);
|
|
```
|
|
|
|
New:
|
|
|
|
```js
|
|
'use strict';
|
|
const db = require('@arangodb').db;
|
|
const aql = require('@arangodb').aql;
|
|
|
|
function query(propName, uppercase) {
|
|
const results = db._query(aql`
|
|
FOR u IN _users
|
|
SORT u.user ASC
|
|
RETURN u[${propName}]
|
|
`);
|
|
return (
|
|
uppercase
|
|
? results[0].toUpperCase()
|
|
: results[0].toLowerCase()
|
|
);
|
|
}
|
|
|
|
query('user', true);
|
|
```
|
|
|
|
!SECTION Other changes
|
|
|
|
The `console` object in later versions of ArangoDB 2.x implemented a special Foxx console API and would optionally log messages to a collection. ArangoDB 3.0 restores the original behaviour where `console` is the same object available from the [console module](../Appendix/JavaScriptModules/Console.md).
|