File access in Foxx

Files within the service folder should always be considered read-only.You should not expect to be able to write to your service folder ormodify any existing files.

ArangoDB is primarily a database. In most cases the best place to store datais therefore inside the database, not on the file system.

Serving files

The most flexible way to serve files in your Foxx service is to simplypass them through in your router usingthe context object’s fileName method andthe response object’s sendFile method:

  1. router.get("/some/filename.png", function(req, res) {
  2. const filePath = module.context.fileName("some-local-filename.png");
  3. res.sendFile(filePath);
  4. });

While allowing for greater control of how the file should be sent tothe client and who should be able to access it,doing this for all your static assets can get tedious.

Alternatively you can specify file assets that should be served by yourFoxx service directly in the service manifestusing the files attribute:

  1. "files": {
  2. "/some/filename.png": {
  3. "path": "some-local-filename.png",
  4. "type": "image/png",
  5. "gzip": false
  6. },
  7. "/favicon.ico": "bookmark.ico",
  8. "/static": "my-assets-folder"
  9. }

Writing files

It is almost always an extremely bad idea to attempt to modifythe filesystem from within a service:

  • The service folder itself is considered an implementation artefact andmay be discarded and replaced without warning.ArangoDB maintains a canonical copy of each service internally todetect missing or damaged services and restore them automatically.

  • ArangoDB uses multiple V8 contexts to allow handling multipleFoxx requests in parallel. Writing to the same file in a request handlermay therefore cause race conditions and result in corrupted data.

  • Writing to files outside the service folder introduces external state. Ina cluster this will result in coordinators no longer being interchangeable.

  • Writing to files during setup is unreliable because the setup script maybe executed several times or not at all. In a cluster the setup scriptwill only be executed on a single coordinator.

Therefore it is almost always a better option to store files using aspecialized, external file storage serviceand handle file uploads outside Foxx itself.

However in some cases it may be feasible to store smaller files directly inArangoDB documents by using a separate collection.

Due to the way ArangoDB stores documents internally, you should not storefile contents alongside other attributes that might be updated independently.Additionally, large file sizes will impact performance for operationsinvolving the document and may affect overall database performance.

In production, you should avoid storing any files in ArangoDB or handling fileuploads in Foxx. The following example will work for moderate amounts of smallfiles but is not recommended for large files or frequent uploads ormodifications.

To store files in a document you can simply convert the file contentsas a Buffer to a base64-encoded string:

  1. router.post('/avatars/:filename', (req, res) => {
  2. collection.save({
  3. filename: req.pathParams.filename,
  4. data: req.body.toString('base64')
  5. });
  6. res.status('no content');
  7. });
  8. router.get('/avatars/:filename', (req, res) => {
  9. const doc = collection.firstExample({
  10. filename: req.pathParams.filename
  11. });
  12. if (!doc) res.throw('not found');
  13. const data = new Buffer(doc.data, 'base64');
  14. res.set('content-type', 'image/png');
  15. res.set('content-length', data.length);
  16. res.write(data);
  17. });