@sap/xsodata
Version:
Expose data from a HANA database as OData V2 service with help of .xsodata files.
152 lines (133 loc) • 4.54 kB
JavaScript
;
const async = require('async');
const NotSupportedError = require('./../../utils/errors/http/notSupported');
const contentTypeTools = require('./../../utils/checkContentType');
const api = (module.exports = {
validate: validate,
_validateHttpHeader: _validateHttpHeader,
_validateAcceptHeader: _validateAcceptHeader,
});
/**
* Validates the http request. Validation is done by validate http accept header.
*
*@param {Object} context The xsodata context
*@param {Function} done Callback called on finish. Expect following signature:
* function(error, context){}
*/
function validate(context, done) {
const validationStrategy = getValidationStrategy(context);
context.logger.silly('httpRequestValidator', 'validate');
async.waterfall(validationStrategy, function (err, result) {
done(err, result);
});
}
/**
* Validates the http request header in general. I.e. if headers exists.
*
*@param {Object} context The xsodata context
*@param {Function} done Callback called on finish. Expect following signature:
* function(error, context){}
*/
function _validateHttpHeader(context, done) {
context.logger.silly('httpRequestValidator', 'validateHttpHeader');
if (!context.request || !context.request.headers) {
return done(
new NotSupportedError('A valid http Accept header must be provided')
);
}
done(null, context);
}
/**
* Validates the http request accept header. This method validates if the current provided
* http accept header is available and is supported.
*
*@param {Object} context The xsodata context
*@param {Function} done Callback called on finish. Expect following signature:
* function(error, context){}
*/
function _validateAcceptHeader(context, done) {
const acceptHeader =
context.request.headers['accept'] || context.request.headers['Accept'];
context.logger.silly('httpRequestValidator', 'validateAcceptHeader');
if (!acceptHeader) {
return done(
new NotSupportedError('A valid http Accept header must be provided')
);
}
let contentType;
try {
contentType = contentTypeTools.checkEntry(
context.request,
getCustomFormat(context)
);
} catch (ex) {
return done(
new NotSupportedError(
"Provided http Accept header '" +
acceptHeader +
"' is not supported",
context,
ex
)
);
}
if (contentType === contentTypeTools.cTypes.ctJson) {
return done(null, context);
}
return done(
new NotSupportedError(
"Provided http Accept header '" +
acceptHeader +
"' is not supported"
)
);
}
/**
* Returns true if the current request is a batch request. A request is a batch request if
* the request url ends with $batch.
*
*@param {Object} context The xsodata context
*@returns {Boolean} True if current request url endwith $batch else false
*/
function isBatchRequest(context) {
if (
!context.uriTree.segments.decoded ||
context.uriTree.segments.decoded.length === 0
) {
return false; // call to service document
}
return context.uriTree.segments.decoded[0].toLowerCase() === '$batch';
}
/**
* Returns the current validation strategy. The validation strategy which will be used for
* validation depends on the kind of request sent.
*
*@param {Object} context The xsodata context
*/
function getValidationStrategy(context) {
let initialStrategy;
context.logger.silly('httpRequestValidator', 'getValidationStrategy');
// Initial strategy is needed to inject context into async.waterfall()
initialStrategy = [
function (callback) {
callback(null, context);
},
];
if (context.request.method === 'POST' && !isBatchRequest(context)) {
// Adding validation strategies if http method is POST and request is not a batch req.
return initialStrategy.concat([
api._validateHttpHeader,
api._validateAcceptHeader,
]);
}
return initialStrategy;
}
/**
* Returns value of the custom 'format' URL parameter.
*/
function getCustomFormat(context) {
const queryParameters = context.uriTree.queryParameters;
if (queryParameters) {
return queryParameters['format'];
}
}