Singleton instance of UnityBase application. Allow direct access to the database connections, blob stores, HTTP endpoints (full control on HTTP request & response) registration, read domain and server config.

Mixes EventEmitter, and emit:

  • launchEndpoint:before with parameters: (req, resp, endpointName)
  • endpointName + ':before' event before endpoint handler execution
  • endpointName + ':after' event in case neither exception is raised nor App.preventDefault() is called
  • launchEndpoint:after with parameters: (req, resp, endpointName, defaultPrevented)

To prevent endpoint handler execution App.preventDefault() can be used inside :before handler.

  
      const App = require('@unitybase/ub').App
// Register public (accessible without authentication) endpoint
App.registerEndpoint('echoToFile', echoToFile, false)

// write custom request body to file FIXTURES/req and echo file back to client
// @ param {THTTPRequest} req
// @ param {THTTPResponse} resp
function echoToFile (req, resp) {
  var fs = require('fs')
  fs.writeFileSync(path.join(FIXTURES, 'req'), req.read('bin'))
  resp.statusCode = 200
  resp.writeEnd(fs.readFileSync(path.join(FIXTURES, 'req'), {encoding: 'bin'}))
}

//Before getDocument requests
//@ param {THTTPRequest} req
//@ param {THTTPResponse} resp
function doSomethingBeforeGetDocumentCall(req, resp){
  console.log('User with ID', Session.userID, 'try to get document')
}
// Adds hook called before each call to getDocument endpoint
App.on('getDocument:before', doSomethingBeforeGetDocumentCall)

//
//After getDocument requests
//@ param {THTTPRequest} req
//@ param {THTTPResponse} resp
function doSomethingAfterGetDocumentCall(req, resp){
  params = req.parsedParameters
  console.log('User with ID', Session.userID, 'obtain document using params',  params)
}
App.on('getDocument:after', doSomethingAfterGetDocumentCall)
  
Mixes In:

# new ServerApp ()

Members

# blobStores static

BLOB stores methods. For usage examples see:

# dbConnections : Object.<string, DBConnection> static

Databases connections pool

# defaultLang : String static

Application default language

# domainInfo : UBDomain static

Extended information about application domain (metadata)

# emitterEnabled : Boolean deprecated static

Is event emitter enabled for App singleton. Default is false

Starting from 1.11 this property ignored (always TRUE)

# endpointContext : Object static

Endpoint context. Application logic can store here some data what required during single HTTP method call; Starting from UB@5.17.9 server reset App.endpointContext to {} after endpoint implementation execution, so in the beginning of execution it's always empty

App.endpointContext.MYMODEL_mykey = 'some value we need to share between different methods during a single user request handling'

# externalURL : String static

URL that the User from the internet will use to access your server. To be used in case server is behind a reverse proxy

# fsObserve static

Observe a file system operation time (exposed as prometheus unitybase_fs_operation_duration_seconds histogram).

WARNING do not use a full file path - use a folder name or better a mnemonic name (BLOB store name for example). Amount of metric labels SHOULD be as less as possible. The same is true for operation`s names.

See fileSystemBlobStore for real life usage example.

# httpCallObserve static

Observe a HTTP client operation time (exposed as prometheus unitybase_httpext_duration_seconds histogram).

http module automatically observe each request, passing host as uri parameter. Method can be called manually in case some part of path should be observed also.

WARNING do not use a full path - use a part what identify an endpoint without parameters. Amount of metric labels SHOULD be as less as possible. The same is true for operation`s names.

# localIPs static

List of a local server IP addresses CRLF (or CR for non-windows) separated

# package : Object static

Application package.json content (parsed)

# serverConfig : Object static

Server configuration - result of argv.getServerConfiguration

Name Type Description
httpServer Object

HTTP server config

application Object
application.name string
application.defaultLang string
application.domain Object
application.domain.models Array
application.domain.supportedLanguages Array.<string>
application.customSettings Object
uiSettings Object

Section uiSettings of ubConfig

security Object

# serverPublicCert : string static

Defense edition only, Base64 encoded public server certificate

Contains non empty value in case security.dstu.trafficEncryption === true and key name defined in security.dstu.novaLib.keyName

# serverURL : String static

Full URl HTTP server is listen on (if HTTP server enabled, else - empty string)

# staticPath : String static

Full path to application static folder if any, '' if static folder not set

Methods

# addAppLevelMethod () static deprecated

Use App.registerEndpoint instead

# authFromRequest (noHTTPBodyInRespboolean, doSetOutCookieboolean) → Boolean static

Try retrieve or create new session from request headers. Return true if success, false if more auth handshakes is required. In case of invalid credential throw security exception

Arguments:
  • noHTTPBodyInResp: boolean

    If true do not write a uData to the HTTP response

  • doSetOutCookie: boolean

    If true set a out authorization cookie on success response (Negotiate only)

# dbCommit (connectionNameoptString) → Boolean static

Commit active database transaction if any. In case connectionName is not passed will commit all active transactions for all connections. Return true if transaction is committed, or false if database not in use or no active transaction.

Arguments:

# dbInTransaction (connectionNameString) → Boolean static

Check database are used in current endpoint context and DB transaction is already active.

Arguments:

# dbRollback (connectionNameoptString) → Boolean static

Rollback active database transaction if any. In case connectionName is not passed will rollback all active transactions for all connections. Return true if transaction is rollback'ed, or false if database not in use or no active transaction.

Arguments:

# dbStartTransaction (connectionNameString) → Boolean static

Start a transaction for a specified database. If database is not used in this context will create a connection to the database and start transaction.

For Oracle with DBLink first statement to DBLink'ed table must be either update/insert/delete or you MUST manually start transaction to prevent "ORA-01453: SET TRANSACTION be first statement"

Arguments:

# deleteFromFTSIndex (entityNameString, instanceIDNumber) static

Delete row from FTS index for exemplar with instanceID of entity entityName (mixin fts must be enabled for entity)

Arguments:

# els (entityCodeString, methodCodeString) → boolean static

Check Entity-Level-Security for specified entity/method

Arguments:
  
      if App.els('uba_user', 'insert'){
       // do something
}
  

# enterCriticalSection (csIndexnumber) static

Waits for ownership of the specified critical section object. The function returns when the calling thread is granted ownership.

** IMPORTANT** A thread must call App.leaveCriticalSection once for each time that it entered the critical section.

Arguments:
  • csIndex: number

    A critical section index returned by App.registerCriticalSection

# getUISettings () → string static deprecated

Use App.serverConfig.uiSettings: Object instead

Return stringified JSON specified in serverConfig.uiSettings

# globalCacheGet (keyString) → String static

Get value from global cache. Global cache shared between all threads.

Return '' (empty string) in case key not present in cache.

Arguments:

# globalCachePut (keyString, valueString) static

Put value to global cache.

Arguments:
  • key: String

    Key to put into

  • value: String| null

    Value to put into this key. If === null then key will be remover from cache

# grantEndpointToRole (endpointNameString, roleCodeString) → boolean static

Grant endpoint to role

Return:

true if endpoint exists and role not already granted, false otherwise

Arguments:

# leaveCriticalSection (csIndexnumber) static

Releases ownership of the specified critical section

Arguments:

# logEnter (methodNamestring) static

Enter a log recursion call. ** IMPORTANT** A thread must call App.logLeave once for each time that it entered the log recursion

Arguments:
  
      function wrapEnterLeave(enterText, originalMethod) {
    return function(ctx) {
      App.logEnter(enterText)
      try {
        originalMethod(ctx)
      } finally {
        App.logLeave()
      }
    }
  }
  

# logLeave () static

Exit a log recursion call

# logout () static

Logout a current user (kill current session)

# preventDefault () static

Accessible inside app-level :before event handler. Call to prevent default method handler. In this case developer are responsible to fill response object, otherwise HTTP 400 is returned.

# registerCriticalSection (csNamestring) → number static

Register a named critical section. Can be done only in initialization mode. In case section with the same name already registered in another thread - returns existed CS index

All threads MUST register section in the same way, do not put call into condition what may evaluates too the different values in the different threads.

Arguments:
  • csName: string

    Critical section name

  
      const App = require('@unitybase/ub').App
// critical section must be registered once in the moment modules are evaluated without any conditions
const MY_CS = App.registerCriticalSection('SHARED_FILE_ACCESS')

function concurrentFileAccess() {
  // prevents mutual access to the same file from the different threads
  App.enterCriticalSection(FSSTORAGE_CS)
  try {
    const data = fs.readfileSync('/tmp/concurrent.txt', 'utf8')
    // do some operation what modify data
    fs.writefileSync('/tmp/concurrent.txt', data)
  } finally {
    // important to leave critical section in finally block to prevent forever lock
    App.leaveCriticalSection(FSSTORAGE_CS)
  }
}
  

# registerEndpoint (endpointNameString, handlerfunction, authorizationRequiredoptboolean, isDefaultoptboolean, bypassHTTPLoggingoptboolean) static

Register a server endpoint. One of the endpoints can be default endpoint - it will be used as a fallback in case URL do not start with any of known endpoints name.

Exceptions inside endpoint handler are intercepted by UB server. In case exception is occurred server will rollback any active DB transactions and serialize an exception message to response depending on server execution mode:

  • for dev mode - original exception text will be serialized (for debugging purpose)
  • for production mode - in case exception message is wrapped into <<<..>>> then this message will be serialized, if not - text will be always Internal server error (for security reason)

Recommended way to throw an handled error inside endpoint handler is throw new UB.UBAbort('.....')

Arguments:
  • endpointName: String
  • handler: function
  • authorizationRequired = true: boolean

    If true UB will check for valid Authorization header before execute endpoint handler

  • isDefault = false: boolean
  • bypassHTTPLogging = false: boolean

    Do not put HTTP body into log (for example if body contains sensitive information, like password)

  
      // Write a custom request body to file FIXTURES/req and echo file back to client
 // @param {THTTPRequest} req
 // @param {THTTPResponse} resp
 //
 function echoToFile(req, resp) {
   var fs = require('fs');
   fs.writeFileSync(FIXTURES + 'req', req.read('bin'));
   resp.statusCode = 200;
   resp.writeEnd(fs.readFileSync(FIXTURES + 'req', {encoding: 'bin'}));
 }
 App.registerEndpoint('echoToFile', echoToFile);
  

# removeUserSessions (userIDnumber) → boolean static

Remove all user sessions (logout user).

Return:

true if user had had any session

Arguments:

# serviceMethodByPassAuthentication () static deprecated

Use App.registerEndpoint instead

# updateFTSIndex (entityNameString, instanceIDNumber) static

Update FTS index for for exemplar with instanceID of entity entityName (mixin fts must be enabled for entity). In case row dose not exist in FTS perform insert action automatically.

Arguments:

Events

# endpointName:after  --> (reqTHTTPRequest, respTHTTPResponse, endpointNamestring)

Fires after endpoint execution. In example below handler is called before each getDocument execution

Arguments:

# endpointName:before  --> (reqTHTTPRequest, respTHTTPResponse, endpointNamestring)

Fires before endpoint execution. In example below handler is called before each getDocument execution

  
      const UB = require('@unitybase/ub')
const App = UB.App
function doSomethingBeforeGetDocumentCall(req, resp){
  console.log('User with ID', Session.userID, 'try to get document')
}
// Adds hook called before each call to getDocument endpoint
App.on('getDocument:before', doSomethingBeforeGetDocumentCall)
  
Arguments:

# domainIsLoaded  --> ()

Fires for an UB.App just after all domain entities (all *.meta) are loaded into server memory and all server-side js are evaluated (for each working thread).

On this stage you can subscribe on a cross-model handles.

# enterConnectionContext  --> ()

Fires (by native code) for an UB.App just after HTTP request context tries to got a DB connection for the first time

On this stage DB session properties, specific for a current Session can be sets. For example multitenancy mixin subscribes for this event and sets a ub_tenantID DB session variable value to Session.tenantID

# launchEndpoint:after  --> (reqTHTTPRequest, respTHTTPResponse, endpointNamestring)

Fires after any endpoint execution

Arguments:

# launchEndpoint:before  --> (reqTHTTPRequest, respTHTTPResponse, endpointNamestring)

Fires before any endpoint execution

Arguments: