NatLibFi/melinda-api-client

View on GitHub
lib/index.js

Summary

Maintainability
D
1 day
Test Coverage
/**
*
* @licstart  The following is the entire license notice for the JavaScript code in this file. 
*
* JS client for using Melinda API (Union catalogue of the National library of Finland)
*
* Copyright (c) 2015-2017 University Of Helsinki (The National Library Of Finland)
*
* This file is part of melinda-api-client
*
* melinda-api-client is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
* @licend  The above is the entire license notice
* for the JavaScript code in this file.
*
**/

(function (root, factory) {
  "use strict";
  if (typeof define === 'function' && define.amd) {
    define([
      'q',
      'axios/dist/axios.amd',
      '@natlibfi/marc-record-serializers',
      '@natlibfi/marc-record',
      'url-join/lib/url-join'
    ], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(
      require('q'),
      require('axios'),
      require('@natlibfi/marc-record-serializers'),
      require('@natlibfi/marc-record'),
      require('url-join'),
      require('btoa'),
      require('xmldom'));  // jshint ignore:line
  }
}(this, function (Q, axios, marc_record_serializers, marc_record, urljoin, btoa, xmldom) {
  "use strict";

  function constructor(config) {

    marc_record.MarcRecord.setValidationOptions({subfieldValues: false});

    function loadRecord(id, params, raw) {
      var defer = Q.defer();
      raw = raw || false;

      var url = urljoin(config.endpoint, 'bib', id);

      var opts = {};
      if (params !== undefined) {
        opts.params = params;
      }

      console.log('Getting url ' + url);
      axios.get(url, opts).then(function (response) {
        // console.log(response);
        if (raw === true) {
          return defer.resolve(response);
        }

        try {
          //console.log(response);
          var record = marc_record_serializers.MARCXML.from(response.data);
          defer.resolve(record);
        } catch (e) {
          //console.log("ERROR");
          defer.reject(e);
        }


      }).catch(axiosErrorHandler(defer));

      return defer.promise;
    }

    function loadChildRecords(id, params, raw) {

      var defer = Q.defer();
      raw = raw || false;

      var url = urljoin(config.endpoint, 'bib', id, 'children');
      console.log(`Fetching subrecords from ${url}`);

      var opts = {};
      if (params !== undefined) {
        opts.params = params;
      }

      axios.get(url, opts).then(function (response) {
        console.log(response.status);

        var collection_children,
          serializer = new xmldom.XMLSerializer(),
          records = [];

        if (raw === true) {
          return defer.resolve(response);
        }

        try {

          collection_children = new xmldom.DOMParser()
            .parseFromString(response.data)
            .getElementsByTagName('record');

           for (var i = 0; i < collection_children.length; i++) {
            records.push(marc_record_serializers.MARCXML.from(
              serializer.serializeToString(collection_children.item(i))
            ));
          }

          defer.resolve(records);

        } catch (e) {
          defer.reject(e);
        }


      }).catch(axiosErrorHandler(defer));

      return defer.promise;
    }

    function createRecord(record, params) {
      var defer = Q.defer();

      record.fields = record.fields.filter(function (f) {
        return f.tag !== "001";
      });

      var url = urljoin(config.endpoint, 'bib');

      try {
        var inMARCXML = marc_record_serializers.MARCXML.to(record);

        var opts = {
          headers: {
            "Content-Type": "text/xml",
            "Authorization": "Basic " + btoa(config.user + ":" + config.password)
          },
          params: params
        };

        axios.post(url, inMARCXML, opts).then(function (response) {
          //console.log(response);
          var parsedResponse = parseResponse(response.data);
          if (parsedResponse.errors.length === 0) {
            defer.resolve(parsedResponse);
          } else {
            defer.reject(parsedResponse);
          }
        }).catch(axiosErrorHandler(defer));
      } catch (e) {

        defer.reject(e);
      }

      return defer.promise;
    }

    function updateRecord(record, params) {
      var defer = Q.defer();

      var idFields = record.fields.filter(function (f) {return f.tag == "001";});
      if (idFields.length !== 1 || isNaN(idFields[0].value)) {
        defer.reject(new Error("Could not determine record id"));
        return defer.promise;
      }

      var id = idFields[0].value;
      var url = urljoin(config.endpoint, 'bib', id);

      try {
        var inMARCXML = marc_record_serializers.MARCXML.to(record);

        var opts = {
          headers: {
            "Content-Type": "text/xml",
            "Authorization": "Basic " + btoa(config.user + ":" + config.password)
          },
          params: params
        };

        axios.put(url, inMARCXML, opts).then(function (response) {
          var parsedResponse = parseResponse(response.data);
          if (parsedResponse.errors.length === 0) {
            defer.resolve(parsedResponse);
          } else {
            defer.reject(parsedResponse);
          }

        }).catch(axiosErrorHandler(defer));
      } catch (e) {

        defer.reject(e);
      }

      return defer.promise;

    }

    function parseResponse(response) {
      var parser = new xmldom.DOMParser();
      var doc = parser.parseFromString(response);

      var messages = textContents(doc.getElementsByTagName('message')).map(parseMessage);
      var errors = textContents(doc.getElementsByTagName('error')).map(parseMessage);
      var triggers = textContents(doc.getElementsByTagName('trigger')).map(parseMessage);
      var warnings = textContents(doc.getElementsByTagName('warning')).map(parseMessage);


      var parsedResponse = {
        messages: messages,
        errors: errors,
        triggers: triggers,
        warnings: warnings
      };

      var successMessages = messages.filter(function (message) {
        return message.code == '0018';
      });

      var idList = successMessages.map(function (message) {
        var match = /^Document: ([0-9]+) was updated successfully.$/.exec(message.message);
        if (match) {
          return match[1];
        }
      }).filter(function (f) {return f !== undefined;});

      if (idList.length > 1) {
        throw new Error("Multiple ids from success messages");
      }
      if (idList.length == 1) {
        parsedResponse.recordId = idList[0];
      }

      return parsedResponse;

      function parseMessage(alephMessage) {
        var match = /\[([0-9]+)\](.*)/.exec(alephMessage);
        if (match !== null) {
          return {
            code: match[1],
            message: match[2].trim()
          };
        } else {
          return {
            code: -1,
            message: "melinda-api-client unable to parse: " + alephMessage
          };
        }
      }

      function textContents(nodeList) {
        var contents = [];
        Array.prototype.slice.call(nodeList).forEach(function (node) {
          Array.prototype.slice.call(node.childNodes).forEach(function (node) {
            if (node.nodeType === 3) { //3 -> textNode
              contents.push(node.data);
            }

          });
        });
        return contents;

      }

    }


    function axiosErrorHandler(deferred) {
      return function (axiosErrorResponse) {
        // console.log(axiosErrorResponse);
        if (axiosErrorResponse instanceof Error) {
          return deferred.reject(axiosErrorResponse);
        }

        var error = new Error(axiosErrorResponse.statusText);
        error.status_code = axiosErrorResponse.status;
        deferred.reject(error);
      };
    }

    return {
      loadRecord: loadRecord,
      loadChildRecords: loadChildRecords,
      updateRecord: updateRecord,
      createRecord: createRecord
    };

  }

  return constructor;
}));