fms-api-client
Version:
A FileMaker Data API client designed to allow easier interaction with a FileMaker database from a web environment.
147 lines (135 loc) • 4.8 kB
JavaScript
;
const axios = require('axios');
const axiosCookieJarSupport = require('axios-cookiejar-support').default;
const fs = require('fs');
const path = require('path');
const toArray = require('stream-to-array');
const { CookieJar } = require('tough-cookie');
const mime = require('mime-types');
const { v4: uuidv4 } = require('uuid');
const _ = require('lodash');
const { interceptResponse } = require('./request.service')
const instance = axios.create();
axiosCookieJarSupport(instance);
/**
* @class Container Service
*/
/**
* Attach Interceptors to Axios instance
* @param {Any} response Web publishing response.
* @param {Any} error We publishing error.
*/
instance.interceptors.response.use(
response => interceptResponse(response),
error => handleError(error)
);
/**
* @function handleError
* @private
* @memberof Container Service
* @description handles errors from the Web Publishing service by ensuring the error is an object.
* @param {Error} error The error recieved from the Web Publishing service.
* @return {Object} An object with a code and a message.
*/
const handleError = error =>
Promise.reject({ code: 100, message: error.message });
/**
* @function transport
* @private
* @memberof Container Service
* @description This function retrieves container data from the FileMaker WPE.
* @see writeFile
* @see writeBuffer
* @param {String} url The url to use for retrieval.
* @param {String} destination The file's destination. Send buffer if it should be set to buffer.
* @param {String} name The name of the file.
* @param {Object} [parameters] Request configuration parameters.
* @return {Promise} A promise which will resolve to the file.
*/
const transport = (url, destination, name, parameters = {}) =>
instance
.get(
url,
Object.assign(
{
jar: new CookieJar(),
responseType: 'stream',
withCredentials: true
},
parameters
)
)
.then(response => {
const filename = path.extname(name)
? name
: `${name}.${mime.extension(response.headers['content-type'])}`;
return destination && destination !== 'buffer'
? writeFile(response.data, filename, destination)
: bufferFile(response.data, filename);
});
/**
* @function writeFile
* @private
* @memberof Container Service
* @description This function will write a file to the filesystem.
* @param {Buffer} stream The stream of data to write.
* @param {String} name The file's name and extension.
* @param {String} destination The destination path to write the file.
* @return {Promise} A promise which will resolve with file path and name.
*/
const writeFile = (stream, name, destination) =>
new Promise((resolve, reject) => {
const output = fs.createWriteStream(path.join(destination, name));
output.on('error', error => reject({ message: error.message, code: 100 }));
output.on('finish', () =>
resolve({ name, path: path.join(destination, name) })
);
stream.pipe(output);
});
/**
* @function bufferFile
* @private
* @memberof Metadata Service
* @description This function will write a stream to a buffer object.
* @param {Stream} stream The url to use for retrieval.
* @param {String} name The name and extension of the file.
* @return {Promise} A promise which will resolve with file path and name.
*/
const bufferFile = (stream, name) =>
toArray(stream).then(parts => ({ name, buffer: Buffer.concat(parts) }));
/**
* @function containerData
* @public
* @memberof Metadata Service
* @description This function retrieves container data from the FileMaker WPE.
* @see transport
* @param {Object|Array} data The response recieved from the FileMaker DAPI.
* @param {String} field The container field name to target. This can be a nested property.
* @param {String} destination "buffer" if a buffer object should be returned or the path to write the file.
* @param {String} name The field to use for the file name or a static string.
* @param {Object=} parameters Request configuration parameters.
* @param {Number=} parameters.timeout a timeout for the request.
* @return {Promise} a promise which will resolve to the file data.
*/
const containerData = (data, field, destination, name, parameters) => {
return Array.isArray(data)
? Promise.all(
data.map(datum =>
transport(
_.get(datum, field),
destination,
_.get(datum, name, datum.recordId || uuidv4()),
parameters
)
)
)
: transport(
_.get(data, field),
destination,
_.get(data, name, data.recordId || uuidv4()),
parameters
);
};
module.exports = {
containerData
};