How To Integrate Fieldbook Service with Node.js

683 Views
|
11 May 2016
|
4 min
author avatar
Sergey L.
Copywriter

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.

Fieldbook 1

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 'Skills' fields

Fieldbook 2

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

Fieldbook 3

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.

Fieldbook 4

API setting and description to work with Fieldbook

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

Fieldbook 5

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.

Fieldbook 6

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: '[email protected]',
                            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: '[email protected]',
            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: '[email protected]',
            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!

An image An image
Bad!
An image An image
Strange!
An image An image
Boring!
An image An image
Good!
An image An image
Love it!
(1348 ratings, average: 4.91 out of 5)
Latest articles
Article preview image
Top 5 cybersecurity frameworks in healthcare field
Calendar icon
18 Jul 2019
Clock icon
10 min
Article preview image
15 software outsourcing companies by size
Calendar icon
16 Jul 2019
Clock icon
10 min
Article preview image
Estimating web application development cost
Calendar icon
11 Jul 2019
Clock icon
9 min
Back to top
As s part of our team, be ready for:
An image
Competitive Base Salary
An image
Comprehensive Benefits
An image
Great Work Environment
An image
Drug Free Workplace
Tell us more about yourself