swish-http
Version:
A Swish implementation that tunnels over HTTP
125 lines (118 loc) • 5.92 kB
JavaScript
var client = require('./client');
var parseQuery = client.parseQuery, createQuery = client.createQuery;
function SwishWrapper(store, options) {
if (!(this instanceof SwishWrapper)) return new SwishWrapper(store, options);
this.store = store;
this.options = options || {};
}
SwishWrapper.prototype = {
express: function () {
var store = this.store;
function collectJsonBody(request, callback) {
var data = [];
request.on('data', function (d) {
data.push(d);
});
request.on('end', function () {
data = Buffer.concat(data);
try {
data = JSON.parse(data.toString('utf-8'));
} catch (e) {
return callback(e);
}
return callback(null, data);
});
request.on('error', function (e) {
return callback(e);
});
}
return function (request, response) {
// Don't do fancy decode - just want the raw query string
var query = {};
var queryString = request.url.split('?').slice(1).join('?');
(queryString.match(/[^&=]+(=[^&]*)?/g) || []).forEach(function (pair) {
var key = pair.split('=', 1)[0], value = pair.substring(key.length + 1);
key = decodeURIComponent(key);
value = decodeURIComponent(value);
if (key in query) {
query[key] = [].concat(query[key]).concat(value);
} else {
query[key] = value;
}
});
var obj = parseQuery(query);
if (obj.error) return response.status(400).json(obj);
var schema = obj.schema, options = obj.options;
if (request.method === 'GET') {
if (!schema) return response.status(400).json('Invalid search query');
store.search(schema, options, function (error, results, continueOptions) {
if (error) return response.status(400).json(error.message);
if (continueOptions) {
var nextQuery = createQuery(schema, continueOptions);
var queryParts = [];
for (var key in nextQuery) {
queryParts.push(encodeURIComponent(key) + '=' + encodeURIComponent(nextQuery[key]));
}
var nextUrl = request.originalUrl.replace(/\?.*/, '') + '?' + queryParts.join('&');
response.links({
'next': nextUrl
});
}
response.json(results);
});
} else if (request.method === 'PUT') {
if (!schema) return response.status(400).json('Invalid search query');
collectJsonBody(request, function (error, data) {
if (error) return response.status(400).json(error.message);
store.replace(schema, data, function (error, result) {
if (error) return response.status(400).json(result || error.message);
response.json(result);
});
});
} else if (request.method === 'DELETE') {
if (!schema) return response.status(400).json('Invalid search query');
store.remove(schema, function (error, result) {
if (error) return response.status(400).json(result || error.message);
response.json(result);
});
} else if (request.method === 'PATCH') {
if (!schema) return response.status(400).json('Invalid search query');
collectJsonBody(request, function (error, data) {
if (error) return response.status(400).json(error.message);
var contentType = request.headers['content-type'].replace(/;.*/, '');
if (contentType === 'application/merge-patch+json') {
store.update(schema, data, function (error, result) {
if (error) return response.status(400).json(result || error.message);
response.json(result);
});
} else if (contentType === 'application/json-patch+json') {
store.patch(schema, data, function (error, result) {
if (error) return response.status(400).json(result || error.message);
response.json(result);
});
} else {
response.status(415).json("Invalid PATCH type: " + contentType);
}
});
} else if (request.method === 'POST') {
collectJsonBody(request, function (error, data) {
if (error) return response.status(400).json(error.message);
if (Array.isArray(data)) {
store.createMultiple(data, options, function (error, result) {
if (error) return response.status(400).json(result || error.message);
response.json(result);
});
} else {
store.create(data, options, function (error, result) {
if (error) return response.status(400).json(result || error.message);
response.json(result);
});
}
});
} else {
return response.status(405).json('Unknown method: ' + request.method);
}
};
}
};
module.exports = SwishWrapper;