How To Integrate Fieldbook Service with Node.js

Updated 27 Oct 2022
3 Min
3893 Views

Things happen, you may need some external service to store certain data, both for the simplicity of filing and storage optimization. Therefore, I decided to write an application prototype, where it was necessary to use the Fieldbook service as a repository for some data.

What is Fieldbook?

The answer is that simple: it is the service enabling to store data in tabular form.

Not to be confused with spreadsheets, which are customized to accounting and finance, Fieldbook is used for creating tracking lists. The grouped view is tailor made for tracking a workflow. Each row in Fieldbook can be viewed in a full-screen detail page, where you can add as much detail as needed.

Moreover, in Fieldbook, you can search, sort, filter and save those views for further work or share with the team. If you have to view and edit related items like assigned tasks or contacts for a company, you can link the sheets.

Data structure in Fieldbook

Let's get back to the project. For the prototype, I decided to create three tables:

1. users 
2. teams 
3. goalscorers

Table 'Team' contains 'Name' and 'Scores' fields

When creating tables, you need to set Numeric ID in the column id to get the main key autoincrement. It is needed to determine the record number in the database. You can find a field spreadsheet_id on the server in the tables.

API setting and description to work with Fieldbook

Fieldbook provides developers with API. You can see the basic examples by pressing 'API'.

In this window, you can test work with tables. Simply by clicking on Manage API access, you can take the base URL for the API. You can also allow access to the API and generate a new API key.

You can read more details on the API here.

Description of Webhooks and logic

The task was pretty simple -- to display lists of teams and goalscorers. By pressing the button of team and goalscorer adding, I updated the entry in the Fieldbook, using the appropriate API. When the table is updated the API responsible for the data in the database update was evoked. Authorization was realized with Radis sessions.

I used the AngularJS framework as a client framework and Node.js as a server one.

We declare routes to API functions of our server:

/**
     * Login
     */
    app.post('/api/v1/auth', auth, function (req, res, next) {
        res.send({});
    });

 /**
     * Logout
     */
    app.post('/api/v1/logout', controllers.v1.users.logout);

    // static links
    app.get('/', controllers.static.index);

    /**
     * Users
     */
    app.route('/api/v1/users')
        .get(checkAuth, controllers.v1.users.modelGet)
        .put(controllers.v1.users.createUsers)
        .post(checkAuth, function (req, res) {
            res.send({});
        });

    app.route('/api/v1/users/current')
        .get(checkAuth, controllers.v1.users.getCurrent);


    /**
     * Webhooks
     */
    app.route('/api/v1/webhooks')
        .get(controllers.v1.webhooks.getWebhooks)
        .post(controllers.v1.webhooks.addWebhook)
        .delete(controllers.v1.webhooks.removeWebhook);

    app.route('/api/v1/webhooks/sync')
        .post(controllers.v1.webhooks.syncWebhook);

 /**
     * Another routes
     */
    app.get('*', controllers.static.index);

To begin with, connect the necessary files and libraries, as well as add basic configs to Fieldbook.

'use strict';
const _            = require('lodash'),
    co             = require('co'),
    BaseController = require('./baseController'),
    helper         = require('./../../utils/helperService'),
    db             = require('./../../models'),
    config         = require('./../../config/config'),
    Fieldbook      = require('node-fieldbook');

let book = new Fieldbook({
    username: 'key-1',
    password: 'password',
    book: 'bookId'
});

let spreadsheetModels = {};

Code for working with fieldbook:

class WebhooksController extends BaseController {
// initialize constructor with necessaries methods, which will be called
    constructor(options) {
        super(options);
        this.getWebhooks = [this._getWebhooks];
        this.addWebhook = [this._addWebhook];
        this.syncWebhook = [this._syncWebhook];
        this.removeWebhook = [this._removeWebhook];
        helper.emitter.on('db:loadEnd', ()=> {
            spreadsheetModels.teams = db.models.Team;
            spreadsheetModels.users = db.models.User;
            spreadsheetModels.goalscorers = db.models.Goalscorer;
        });
    }
// you need to register webhook for sending data from fieldbook to server
    _addWebhook(req, res, next) {
        co(function *() {
            let webhook = yield book.addWebhook({
                url: config.server.baseURL + '/api/v1/webhooks/sync',
                actions: ['create', 'update', 'destroy']
            });

            if (webhook) {
                return res.json(webhook);
            }

            res.json({});
        }).catch(err => next(err));
    }

// get list of webhooks
_getWebhooks(req, res, next) {
        co(function *() {
            let webhooks = yield book.getWebhooks({});

            if (webhooks) {
                return res.json(webhooks);
            }

            res.json({});
        }).catch(err => next(err));
    }
//removing webhook
    _removeWebhook(req, res, next) {
        co(function *() {
            let webhookId = req.query.webhookId;
            let webhookRes = yield book.deleteWebhook(webhookId);

            if (webhookRes) {
                return res.json(webhookRes);
            }

            res.json({});
        }).catch(err => next(err));
    }

//basic method for synchronize data with server
    _syncWebhook(req, res, next) {
        co(function *() {
            let objName = _.keys(req.body.changes)[0];
            let destroyObjects = [];
            let updateObjects = [];
            let createObjects = [];
            let promises = [];
            let resultCreating = false;
    // check
            if (typeof req.body.changes[objName].destroy != 'undefined') {
                _.forEach(req.body.changes[objName].destroy, function(object, i) {
                    let id = object.id.split(" ");
                    id = id[1];
                    destroyObjects.push(id);
                });

                yield spreadsheetModels[objName].remove({spreadsheet_id: destroyObjects});
            }

            if (typeof req.body.changes[objName].update != 'undefined') {
                _.forEach(req.body.changes[objName].update, function(object, i) {
                    let id = object.id.split(" ");
                    id = id[1];

                    let updatingObj = object;
                    delete updatingObj.id;
                    delete updatingObj.record_url;

                    let promise = spreadsheetModels[objName].update({spreadsheet_id: id}, updatingObj);
                    promises.push(promise);
                });

                yield promises;
            }

            if (typeof req.body.changes[objName].create != 'undefined') {
                _.forEach(req.body.changes[objName].create, function(object, i) {
                    let id = object.id.split(" ");
                    id = id[1];

                    let creatingObj = object;
                    delete creatingObj.id;
                    delete creatingObj.record_url;
                    creatingObj.spreadsheet_id = id;
                    createObjects.push(creatingObj);
                });

                resultCreating = yield spreadsheetModels[objName].create(createObjects);
            }

            res.json({});
        }).catch(err => next(err));
    }
}

module.exports = {
    instance: new WebhooksController(),
    class   : WebhooksController
};

The data format sent from Fieldbook

Here are some examples of data format that come when there is a change in the Fieldbook:

If the record deletion takes place, the following data come to a server:

{ changes:
                { teams:
                    { destroy:
                        [ { id: 'team 7',
                            record_url: 'https://fieldbook.com/records/5710d8c948c2550300ed62af',
                            name: 'test2',
                            skills: 32 } ] } },
                        user:
                        { email: 'some@gmail.com',
                            name: 'Some Name',
                            id: '570baf9303823cbc93a00cde' },
                                webhookId: '5710d856a0f1e903007560db' };

If the creation of the record takes place, the following data come to a server:

{ changes:
                { teams:
                { create:
                [ { id: 'team 9',
                    record_url: 'https://fieldbook.com/records/5710d97848c2550300ed62bb',
                    name: 'test3',
                    skills: 22 } ] } },
                user:
                { email: 'some@gmail.com',
            name: 'Some Name',
            id: '570baf9303823cbc93a00cde' },
                webhookId: '5710d856a0f1e903007560db' };

If the record update takes place, the following data come to a server:

{ changes:
                { teams:
                { update:
                    [ { id: 'team 8',
                        record_url: 'https://fieldbook.com/records/5710d8f548c2550300ed62b4',
                        name: 'test3',
                        skills: 132 } ]
                } },
                user:
                { email: 'some@gmail.com',
            name: 'Some Name',
            id: '570baf9303823cbc93a00cde' },
                webhookId: '5710d856a0f1e903007560db' };

The article was intended to show how you can work with Fieldbook service, it is easy to integrate it into the Node.js project, as well as how to synchronize data storage on Fieldbook and the database on the server, thereby automating the content information. I hope it will facilitate the development process for people who are not familiar with this service.

If require any further information or support, please contact us. We'll be happy to hear from you.

Rate this article!
3114 ratings, average: 4.91 out of 5

Comments