Node.JS in Appwrite
Tags: appwrite, node
Published: 2021-10-21 08:28:07

## Introduction
The following article covers the use of the Appwrite Node.JS SDK to develop Appwrite Functions. Appwrite Functions are used to extend the Appwrite Server functionality by providing various options for using custom code. Several different runtimes can be used for this purpose. In the following, the Node.JS runtime will be discussed. Developed and provided Appwrite Functions can be executed manually, based on a CRON schedule or as a reaction to system events.

## Project Creation
Functions are bound to a specific project. To illustrate the various functionalities within this article, a sample project will be created.

In the Appwrite console ([Installation of Appwrite](https://appwrite.io/docs/installation)):
![Project Creation in Appwrite Console](https://i.ibb.co/n0mCyp7/Create-Project.png)

The project created in this way still needs a Database Collection for the examples, which can be created under *Database > Add Collection*:
![Creation of Collection](https://i.ibb.co/ng81Hpq/Create-Collection.png)

This collection should have the following rules:
![Collection Rules](https://i.ibb.co/L1HMvCn/Rules.png)

### API Key
To access the different functionalities of Appwrite within an Appwrite function, a so-called API Key is required. This can be created in the Appwrite console under *API Keys > Add API Key* and should have the permissions `documents.write` and `functions.write` for the following example.

## The Function
Before the function can be created the Node.JS SDK must be installed with `npm install node-appwrite`. Afterwards the function itself can be created. This does not yet contain any code. The code is then created and added to the Appwrite Function in the form of a so-called tag.

### Function Creation
The creation of the Appwrite Function can also be done through the Node.JS SDK, just like the later code. To do this, a new file is created (for example, `create_function.js`) that contains the following code:

Initialize the SDK:
```javascript
const appwrite = require("node-appwrite");

const client = new appwrite.Client();

const functions = new appwrite.Functions(client);

client
    .setEndpoint('[APPWRITE-API-ENDPOINT]')
    .setProject('[APPWRITE-PROJECT-ID]')
    .setKey('[APPWRITE-API-KEY]')
;
```
The `[APPWRITE-API-ENDPOINT]`, `[APPWRITE-PROJECT-ID]` and `[APPWRITE-API-KEY]` values must be adjusted to suit the environment.

Creating the function:
```javascript
let promise =
    functions.create(
        'Create Filename', [], 'node-16.0',
        {
            'SONGS_COLLECTION': '[SONGS-COLECTION-ID]',
            'APPWRITE_ENDPOINT': '[APPWRITE-API-ENDPOINT]',
            'APPWRITE_PROJECT_ID': '[APPWRITE-PROJECT-ID]',
            'APPWRITE_API_KEY': '[APPWRITE-API-KEY]',
        },
        ['database.documents.create', 'database.documents.update'])
;

promise.then( response => {
    console.log(response);  // Success
}, error => {
    console.error(error);   // Failure
});
```
The values `[APPWRITE-API-ENDPOINT]`, `[APPWRITE-PROJECT-ID]`, `[APPWRITE-API-KEY]` and `[SONGS-COLLECTION-ID]` must be adapted to the environment. The ID of the songs collection can be read in the collection settings. Since the Appwrite Functions run in a Docker container, `http://localhost/v1` cannot be used for `[APPWRITE-API-ENDPOINT]`. Here, either the appropriate domain or the IP address of the host system must be used in a local setup.

The function `functions.create()` gets 5 parameters. The first parameter specifies the name of the function. The second one specifies if and if so which users or user roles have the execute permission. The third specifies the runtime to be used. The fourth parameter contains the later needed environment variables and the fifth parameter specifies the events at which the function should be executed. Now the file can be executed with `node create_function.js` and thus the Appwrite Function can be created. In the *Functions* section of the Appwrite console a new function should now have been created.

The pure creation of a function can also be done via the graphical interface of the Appwrite console under *Functions > Add Function*.

### The Function Itself
The code of the Appwrite Function is first created locally and then uploaded together with the required dependencies as a tag of the corresponding Appwrite Function. The following sample code is to enter the filename of the song into the designated rule each time a document of the Songs Collection is created or updated.

To do this, the file `index.js` is created with the following content.

Check whether the created or updated document belongs to the Songs Collection:
```javascript
const DATA = JSON.parse(process.env.APPWRITE_FUNCTION_EVENT_DATA);
const SONGS_COLLECTION = process.env.SONGS_COLLECTION;

const { $id, $collection, title, artist } = DATA;

// Stop if it's not the Songs Collection
if ($collection !== SONGS_COLLECTION) {
    return;
}
```

Initialize the SDK:
```javascript
const appwrite = require("node-appwrite");
const client = new appwrite.Client();
const database = new appwrite.Database(client);

client
    .setEndpoint(process.env.APPWRITE_ENDPOINT)
    .setProject(process.env.APPWRITE_PROJECT_ID)
    .setKey(process.env.APPWRITE_API_KEY)
;
```

To prevent a continuous loop, a check is made to ensure that the song does not already have the correct filename:
```javascript
// Create filename string
let filename = title + " - " + artist + ".mp3";

// Stop if the filename is already correct
if (filename === DATA.filename) {
    return;
}
```

Adapting the Song Document:
```javascript
let promise = database.updateDocument($collection, $id, { filename: filename });

promise.then( response => {
    console.log("Filename changed successfully");
    console.log(response);
}, error => {
    console.error(error);
});
```

To add this code as a tag to the Appwrite Function, the file `index.js` must first be packed together with the dependencies. To do this, the command `tar -zcvf code.tar.gz .` is executed in the same directory as the file and the `node_modules` folder. Then another file `create_tag.js` is created which handles the upload of the tag. It contains the following code.

Initialize the SDK:
```javascript
const appwrite = require('node-appwrite');
const fs = require('fs');

const client = new appwrite.Client();

const functions = new appwrite.Functions(client);

client
    .setEndpoint('[APPWRITE-API-ENDPOINT]')
    .setProject('[APPWRITE-PROJECT-ID]')
    .setKey('[APPWRITE-API-KEY]')
;
```

Again, the `[APPWRITE-API-ENDPOINT]`, `[APPWRITE-PROJECT-ID]` and `[APPWRITE-API-KEY]` values must be adjusted accordingly.

Upload the tag:
```javascript
let promise =
    functions.createTag(
        '[FUNCTION-ID]', 'node index.js', fs.createReadStream(__dirname + '/code.tar.gz')
    )
;

promise.then( response => {
    console.log(response);
}, error => {
    console.error(error);
});
```
The value for `[FUNCTION-ID]` must be adjusted accordingly. The ID of the Appwrite Function can be read in the settings of the function in the Appwrite console.

By executing `node create_tag.js` the tag of the Appwrite Function is added.

## Activating and testing the Appwrite Function
The just uploaded tag must be activated in the Appwrite console under *Functions > Settings of the corresponding function > Activate*.

To test the function, a new song can be added to the Songs Collection in the Appwrite console. After a short time the filename should have been adjusted automatically.

![Create Song](https://i.ibb.co/mqjn6Nx/Create-Song.png)

![New Filename](https://i.ibb.co/ZdLvzJQ/Song-With-Filename.png)

## Further Information
The article covered the basics of creating and using Appwrite Functions with the Node.JS SDK. This example ist just a fraction of what Appwrite Functions can do. More in-depth information can be found here:

* [Getting Started for Server - Appwrite Docs](https://appwrite.io/docs/getting-started-for-server)
* [Functions API for Node.JS SDK - Appwrite Docs](https://appwrite.io/docs/server/functions?sdk=nodejs-default)