UNPKG

@sap/odata-v4

Version:

OData V4.0 server library

162 lines (155 loc) 9.75 kB
'use strict'; const crypto = require('crypto'); const EdmProvider = require('./provider/EdmProvider'); const CsdlJsonProvider = require('./provider/CsdlJsonProvider'); const UriParser = require('./uri/UriParser'); const Service = require('./core/Service'); const Components = require('./core/ComponentManager').Components; const Dispatcher = require('./core/Dispatcher'); const MetadataHandler = require('./handler/MetadataHandler'); const ServiceHandler = require('./handler/ServiceHandler'); const BatchHandler = require('./handler/BatchHandler'); const ResponseContentNegotiator = require('./format/ResponseContentNegotiator'); const RepresentationKinds = require('./format/RepresentationKind').Kinds; const ContentTypes = require('./format/ContentTypeInfo').ContentTypes; const SerializerFactory = require('./serializer/SerializerFactory'); const MetadataXmlSerializer = require('./serializer/MetadataXmlSerializer'); const ServiceJsonSerializer = require('./serializer/ServiceJsonSerializer'); const BatchMultipartSerializer = require('./serializer/BatchMultipartSerializer'); const ErrorJsonSerializer = require('./serializer/ErrorJsonSerializer'); const ErrorXmlSerializer = require('./serializer/ErrorXmlSerializer'); const DebugJsonSerializer = require('./serializer/DebugJsonSerializer'); const DebugHtmlSerializer = require('./serializer/DebugHtmlSerializer'); const RequestValidator = require('./validator/RequestValidator'); const DeserializerFactory = require('./deserializer/DeserializerFactory'); /** * OData service factory to create a full featured odata service */ class ServiceFactory { /** * Creates a full featured odata service. * * @param {Object} metadata The metadata JSON with which the CSDL and then EDM providers can be created * @param {Object} [edmConfiguration={}] A configuration object to configure the behavior of edm artifacts * The example shows the configuration for an EntitySet and Singleton, that are ETAG enabled. * const configuration = { * 'the.edm.namespace': { * 'TheNameOfTheConcurrentEntitySet': { * isConcurrent: true * }, * 'TheNameOfTheConcurrentSingleton': { * isConcurrent: true * } * } * }; * * @returns {Service} A full featured odata service */ static createService(metadata, edmConfiguration = {}) { const edmProvider = new EdmProvider(new CsdlJsonProvider(metadata), edmConfiguration); return new Service(edmProvider) .log(null, entry => entry) .on('request', (request, response, next) => { // This is the default listener called on on each request. next(/* error */); }) .on('debug', (request, response, next) => { // We disable the debug mode by default. // Overwrite this listener to enable debug mode. // To get the info if debug mode is requested // call 'request.getContract().isDebug(): true|false'. request.getContract().enableDebugMode(false); next(/* error */); }) .on('error', (request, response, next, error) => { // This listener subscribes to all error events. // The error object is the original error thrown. // Another error-like object with properties like .statusCode or .message could be passed on. next(null, error); }) .setOdataVersion('4.0') .setMetadataEtag(crypto.createHash('sha256').update(JSON.stringify(metadata)).digest('base64')) .use(Components.DISPATCHER, new Dispatcher()) .use(Components.URI_PARSER, new UriParser(edmProvider)) .use(Components.METADATA_HANDLER, MetadataHandler.read) .use(Components.SERVICE_HANDLER, ServiceHandler.read) .use(Components.BATCH_EXECUTE_HANDLER, BatchHandler.handle) .use(Components.CONTENT_NEGOTIATOR, new ResponseContentNegotiator()) .use(Components.REQUEST_VALIDATOR, new RequestValidator()) .parse(RepresentationKinds.BATCH, ContentTypes.MULTIPART_MIXED, DeserializerFactory.createMultipartMixedDeserializer()) .parse(RepresentationKinds.ENTITY, ContentTypes.JSON, DeserializerFactory.createJsonDeserializer(edmProvider, RepresentationKinds.ENTITY)) .parse(RepresentationKinds.PRIMITIVE, ContentTypes.JSON, DeserializerFactory.createJsonDeserializer(edmProvider, RepresentationKinds.PRIMITIVE)) .parse(RepresentationKinds.PRIMITIVE_COLLECTION, ContentTypes.JSON, DeserializerFactory.createJsonDeserializer(edmProvider, RepresentationKinds.PRIMITIVE_COLLECTION)) .parse(RepresentationKinds.COMPLEX, ContentTypes.JSON, DeserializerFactory.createJsonDeserializer(edmProvider, RepresentationKinds.COMPLEX)) .parse(RepresentationKinds.COMPLEX_COLLECTION, ContentTypes.JSON, DeserializerFactory.createJsonDeserializer(edmProvider, RepresentationKinds.COMPLEX_COLLECTION)) .parse(RepresentationKinds.REFERENCE, ContentTypes.JSON, DeserializerFactory.createJsonDeserializer(edmProvider, RepresentationKinds.REFERENCE)) .parse(RepresentationKinds.PRIMITIVE_VALUE, ContentTypes.TEXT_PLAIN, DeserializerFactory.createTextValueDeserializer()) .parse(RepresentationKinds.ACTION_PARAMETERS, ContentTypes.JSON, DeserializerFactory.createJsonDeserializer(edmProvider, RepresentationKinds.ACTION_PARAMETERS)) // Register the binary parser for all content types sent for representation kind BINARY. // There is special logic for this in the request content negotiator. .parse(RepresentationKinds.BINARY, '', DeserializerFactory.createBinaryDeserializer()) .format(RepresentationKinds.METADATA, ContentTypes.XML, (context, data, options, next) => { next(null, new MetadataXmlSerializer(edmProvider, context.getLogger()).serialize(data)); }) .format(RepresentationKinds.SERVICE, ContentTypes.JSON, (context, data, options, next) => { next(null, new ServiceJsonSerializer(edmProvider).serialize(data)); }) .format(RepresentationKinds.BATCH, ContentTypes.MULTIPART_MIXED, (context, data, options, next) => { const response = context.getResponse(); new BatchMultipartSerializer(data).execute(response); next(); }) .format(RepresentationKinds.ENTITY, ContentTypes.JSON, SerializerFactory.resourceEntity, SerializerFactory.checkJsonParameters) .format(RepresentationKinds.ENTITY_COLLECTION, ContentTypes.JSON, SerializerFactory.resourceEntityCollection, SerializerFactory.checkJsonParameters) .format(RepresentationKinds.PRIMITIVE, ContentTypes.JSON, SerializerFactory.resourcePrimitive, SerializerFactory.checkJsonParameters) .format(RepresentationKinds.PRIMITIVE_COLLECTION, ContentTypes.JSON, SerializerFactory.resourcePrimitiveCollection, SerializerFactory.checkJsonParameters) .format(RepresentationKinds.COMPLEX, ContentTypes.JSON, SerializerFactory.resourceComplex, SerializerFactory.checkJsonParameters) .format(RepresentationKinds.COMPLEX_COLLECTION, ContentTypes.JSON, SerializerFactory.resourceComplexCollection, SerializerFactory.checkJsonParameters) .format(RepresentationKinds.REFERENCE, ContentTypes.JSON, SerializerFactory.resourceReference, SerializerFactory.checkJsonParameters) .format(RepresentationKinds.REFERENCE_COLLECTION, ContentTypes.JSON, SerializerFactory.resourceReferenceCollection, SerializerFactory.checkJsonParameters) .format(RepresentationKinds.PRIMITIVE_VALUE, ContentTypes.TEXT_PLAIN, SerializerFactory.value) .format(RepresentationKinds.BINARY, ContentTypes.TEXT_PLAIN, SerializerFactory.value) .format(RepresentationKinds.COUNT, ContentTypes.TEXT_PLAIN, (context, data, options, next) => { next(null, data.value.toString()); }) .format(RepresentationKinds.NO_CONTENT, null, (context, data, options, next) => { context.getLogger().path('Entering ServiceFactory.format(NO_CONTENT, null)'); context.getLogger().info('No payload available'); next(); }) .format(RepresentationKinds.ERROR, ContentTypes.XML, (error, response, next) => { const data = new ErrorXmlSerializer(error).serialize(); next(null, data); }) .format(RepresentationKinds.ERROR, ContentTypes.JSON, (error, response, next) => { const data = new ErrorJsonSerializer(error).serialize(); next(null, data); }, SerializerFactory.checkJsonParameters) .format(RepresentationKinds.DEBUG, ContentTypes.JSON, (context, buffer, error, next) => { const data = new DebugJsonSerializer(context, buffer.toString(), error).serialize(); next(null, data); }) .format(RepresentationKinds.DEBUG, ContentTypes.HTML, (context, buffer, error, next) => { const data = new DebugHtmlSerializer(context, buffer.toString(), error).serialize(); next(null, data); }); } } module.exports = ServiceFactory;