Firebase Function to populate Algolia
Tags: algolia, firebase, javascript
Published: 2022-02-03 15:25:46

This is a guide for setting up a Firebase Function that will receive data and update an Algolia index. Algolia is a widely used search engine, and populating and updating its data using webhooks and serverless functions is a common approach to integrate with it.

## Setup!

### Firebase setup

* `npm install -g firebase-tools`
* `firebase login`
* `firebase init functions`

This will result in a file, `functions/src/index.js` in which all code will be written. 


### Algolia setup

* Create an account, create an index
* Go to **Settings** and then **API keys** to get the application ID and admin API key. You will also need the name of the index. 


### Add environment variables

Exchange the placeholders in the following command:

```
firebase functions:config:set algolia.application_id="THE APPLICATION ID" algolia.api_key="THE API KEY" algolia.index_name=”THE INDEX NAME”
```

Use `firebase functions:config:get` to display the variables. 

To run the function locally, you'll need to save the variables to a specfic file, using the following command: 
```
firebase functions:config:get > .runtimeconfig.json
```

Reference the variables in code for easy access:
```javascript
const ALGOLIA_APPLICATION_ID = functions.config().algolia.application_id;
const ALGOLIA_API_KEY = functions.config().algolia.api_key;
const ALGOLIA_INDEX_NAME = functions.config().algolia.index_name;
```

### Install dependencies 
* `npm install algoliasearch –save`

...and import it with
* `const algoliasearch = require('algoliasearch');`


## Code!

Add the following function. The `functions.https.onRequest` will expose it and bind it to a specific endpoint. Multiple such function can exist in the same file, but we will only have one. Express is the underlying framework, and the request and response objects work similar to when using Express directly. 

```javascript
export const publishedEntry = functions.https.onRequest(
  async (request, response) => {
    const entry = request.body;
    const index = getAlgoliaIndex();

    if (entry.action === 'DELETED_ENTRY') {
      await index.deleteObject(entry.id);
    } else if (entry.type === 'BOOK') {
      const record = createAlgoliaBookRecord(entry);
      await index.saveObject(record);
    }

    response.send('ok');
  }
);
```
The data sent in contained in the `request.body`. The `getAlgoliaIndex()` method is presented below. The if-statement idenfies the action, or the type, and performs the right action. 


Using the Algolia SDK, the following function will return a SearchIndex. It's on this object that inserts, updates, deletions, etc, of objects are made. The [Algolia documentation](https://www.algolia.com/doc/api-client/methods/indexing/) has all the available methods. 

```javascript
const getAlgoliaIndex = () => {
  const client = algoliasearch(ALGOLIA_APPLICATION_ID, ALGOLIA_API_KEY);
  return client.initIndex(ALGOLIA_INDEX_NAME);
};
```

The `createAlgoliaBookRecord()` filters out just the attributes we're interested in having in our index. A book might have a price, a number of pages, etc, that we do not want to search in. The same result can be achieved by configuring the searchableAttributes in Algolia, however, the more data that is added to the index, the slower it will become. 

Our book model has an ObjectID, that we pass along to Algolia. All Algolia records must have an ObjectId, and if it's not supplied, Algolia will create one.  

```javascript
const createAlgoliaBookRecord = (entry) => {
  const { id, type, name, isbn } = entry;
  return { objectID: id, type, name, isbn };
};
```

## Deploy!

* `npm run deploy`

The deploy script will run the linter, build the code, upload the code and environment variables and deploy it. The URL of the function(s) will be presented. 

### Try it out

POST the following data to the function URL...

```json
{
    "action": "PUBLISHED",
    "type": "BOOK",
    "id": "61fbdf833dbc31f5935dea1b",
    "name": "Some book name",
    "author": "Some Author",
    "isbn": "123456789"
}
```

...and watch how it is added to Algolia.


![A record in Algolia](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p0aauf032u6exi9ia2l8.png)

To test the deletion, only the following data is needed in the POST:

```json
{
    "action": "DELETED_ENTRY",
    "id": "61fbdf833dbc31f5935dea1b"
}
```

Congratulations! You now have a Firebase Function that is updating an Algolia index.