logo.png
mORMot2 API Reference

mormot.rest.core.pas unit

Purpose: REpresentation State Tranfer (REST) Core Types and Classes
- this unit is a part of the Open Source Synopse mORMot framework 2, licensed under a MPL/GPL/LGPL three license - see LICENSE.md

1.1. Units used in the mormot.rest.core unit

Unit NameDescription
mormot.core.baseFramework Core Shared Types and RTL-like Functions
mormot.core.buffersFramework Core Low-Level Memory Buffer Process
mormot.core.dataFramework Core Low-Level Data Processing Functions
mormot.core.datetimeFramework Core Low-Level Date and Time Support
mormot.core.interfacesFramework Core Low-Level Interface/SOLID Processing
mormot.core.jsonFramework Core Low-Level JSON Processing
mormot.core.logFramework Core Logging
mormot.core.osFramework Core Low-Level Wrappers to the Operating-System API
mormot.core.perfFramework Core Performance and Monitoring Classes
mormot.core.rttiFramework Core Low-Level Cross-Compiler RTTI Definitions
mormot.core.textFramework Core Low-Level Text Processing
mormot.core.threadsFramework Core Multi-Threading Support
mormot.core.unicodeFramework Core Low-Level Unicode UTF-8 UTF-16 Ansi Conversion
mormot.core.variantsFramework Core Low-Level Variants / TDocVariant process
mormot.crypt.coreFramework Core Cryptographic Process (Hashing and Cypher)
mormot.crypt.jwtFramework Core JSON Web Tokens (JWT) Support
mormot.crypt.secureFramework Core Authentication and Security Features
mormot.db.coreDatabase Framework Core Types and Classes
mormot.orm.baseObject-Relational-Mapping (ORM) Low-Level Process
mormot.orm.coreObject-Relational-Mapping (ORM) Main Types and Classes
mormot.soa.coreInterface-based SOA Process Core Types and Classes

1.2. mormot.rest.core class hierarchy

TThreadAbstractTRestThreadTSynPersistentLockTRestRunThreadsTRestAcquireExecutionTSynBackgroundTimerTRestBackgroundTimerTOrmTOrmTableDeletedTOrmModificationTAuthUserTAuthGroupTOrmHistoryTObjectTRestUriParamsTRestUriContextTInterfaceResolverTRestESynExceptionERestException
mormot.rest.core class hierarchy

1.3. Objects implemented in the mormot.rest.core unit

ObjectsDescription
ERestExceptionException class raised on TRest issues
TAuthGroupTable containing the available user access rights for authentication
TAuthUserTable containing the Users registered for authentication
TOrmHistoryCommon ancestor for tracking changes on TOrm tables
TOrmModificationCommon ancestor for tracking TOrm modifications
TOrmTableDeletedORM table used to store the deleted items of a versioned table
TRestAbstract REpresentational State Transfer (REST) client/server class
TRestAcquireExecutionUsed to store the execution parameters for a TRest instance
TRestBackgroundTimerTThread able to run one or several tasks at a periodic pace, or do asynchronous interface or batch execution, with proper TRest integration
TRestRunThreadsAccess to the Multi-Threading process of a TRest instance
TRestServerConnectionOpaqueAn opaque connection-specific pointer identifier with a strong type
TRestThreadA simple TThread for doing some process within the context of a REST instance
TRestUriContextAbstract calling context for any Server-Side REST process
TRestUriParamsStore all parameters for a Client or Server method call

1.3.1. TRestAcquireExecution

TRestAcquireExecution = class(TSynPersistentLock)

Used to store the execution parameters for a TRest instance


LockedTimeOut: cardinal;

Ms delay before failing to acquire the lock


Mode: TRestServerAcquireMode;

How read or write operations will be executed


Thread: TSynBackgroundThreadMethod;

Background thread instance (if any)


destructor Destroy; override;

Finalize the memory structure, and the associated background thread


1.3.2. TRestBackgroundTimer

TRestBackgroundTimer = class(TSynBackgroundTimer)

TThread able to run one or several tasks at a periodic pace, or do asynchronous interface or batch execution, with proper TRest integration
- used e.g. by TRest.TimerEnable/AsyncRedirect/AsyncBatchStart methods
- TRest.BackgroundTimer will define one instance, but you may create other dedicated instances to instantiate separated threads


constructor Create(aRest: TRest; const aThreadName: RawUtf8 = ''; aStats: TSynMonitorClass = nil); reintroduce; virtual;

Initialize the thread for a periodic task processing


destructor Destroy; override;

Finalize the thread


function AsyncBatchAdd(Value: TOrm; SendData: boolean; ForceID: boolean = false; const CustomFields: TFieldBits = []; DoNotAutoComputeFields: boolean = false): integer;

Create a new ORM member in a BATCH to be written in a background thread
- should have been preceded by a call to AsyncBatchStart(), or returns -1
- is a wrapper around TRestBatch.Add() sent in the Timer thread, so will return the index in the BATCH rows, not the created TID
- this method is thread-safe


function AsyncBatchDelete(Table: TOrmClass; ID: TID): integer;

Delete an ORM member in a BATCH to be written in a background thread
- should have been preceded by a call to AsyncBatchStart(), or returns -1
- is a wrapper around the TRestBatch.Delete() sent in the Timer thread
- this method is thread-safe


function AsyncBatchRawAdd(Table: TOrmClass; const SentData: RawUtf8): integer;

Append some JSON content in a BATCH to be writen in a background thread
- could be used to emulate AsyncBatchAdd() with an already pre-computed JSON object
- is a wrapper around TRestBatch.RawAdd() sent in the Timer thread, so will return the index in the BATCH rows, not the created TID
- this method is thread-safe


function AsyncBatchStart(Table: TOrmClass; SendSeconds: integer; PendingRowThreshold: integer = 500; AutomaticTransactionPerRow: integer = 1000; Options: TRestBatchOptions = [boExtendedJson]): boolean;

Prepare an asynchronous ORM BATCH process, executed in a background thread
- will initialize a TRestBatch and call TimerEnable to initialize the background thread, following the given processing period (in seconds), or the TRestBatch.Count threshold to call BatchSend
- actual REST/CRUD commands will take place via AsyncBatchAdd, AsyncBatchUpdate and AsyncBatchDelete methods
- only a single AsyncBatch() call per Table is allowed at a time, unless AsyncBatchStop method is used to flush the current asynchronous BATCH
- using a BATCH in a dedicated thread will allow very fast background asynchronous process of ORM methods, sufficient for most use cases


function AsyncBatchStop(Table: TOrmClass): boolean;

Finalize asynchronous ORM BATCH process, executed in a background thread
- should have been preceded by a call to AsyncBatch(), or returns false
- Table=nil will release all existing batch instances


function AsyncBatchUpdate(Value: TOrm; const CustomFields: TFieldBits = []; DoNotAutoComputeFields: boolean = false): integer;

Update an ORM member in a BATCH to be written in a background thread
- should have been preceded by a call to AsyncBatchStart(), or returns -1
- is a wrapper around the TRestBatch.Update() sent in the Timer thread
- this method is thread-safe


procedure AsyncBatchRawAppend(Table: TOrmClass; SentData: TJsonWriter);

Append some JSON content in a BATCH to be writen in a background thread
- could be used to emulate AsyncBatchAdd() with an already pre-computed JSON object, as stored in a TJsonWriter instance
- is a wrapper around TRestBatch.RawAppend.AddNoJsonEscape(SentData) in the Timer thread
- this method is thread-safe


procedure AsyncInterning(Interning: TRawUtf8Interning; InterningMaxRefCount: integer = 2; PeriodMinutes: integer = 5);

Allows background garbage collection of specified RawUtf8 interning
- will run Interning.Clean(2) every 5 minutes by default
- set InterningMaxRefCount=0 to disable process of the Interning instance


procedure AsyncRedirect(const aGuid: TGuid; const aDestinationInterface: IInvokable; out aCallbackInterface; const aOnResult: TOnAsyncRedirectResult = nil); overload;

Define asynchronous execution of interface methods in a background thread
- this method implements any interface via a fake class, which will redirect all methods calls into calls of another interface, but as a FIFO in a background thread, shared with TimerEnable/TimerDisable process
- parameters will be serialized and stored as JSON in the queue
- by design, only procedure methods without any output parameters are allowed, since their execution will take place asynchronously
- of course, a slight delay is introduced in aDestinationInterface methods execution, but the main process thread is not delayed any more, and is free from potential race conditions
- the returned fake aCallbackInterface should be freed before TRest is destroyed, to release the redirection resources
- it is an elegant resolution to the most difficult implementation problem of SOA callbacks, which is to avoid race condition on reentrance, e.g. if a callback is run from a thread, and then the callback code try to execute something in the context of the initial thread, protected by a critical section (mutex)


procedure AsyncRedirect(const aGuid: TGuid; const aDestinationInstance: TInterfacedObject; out aCallbackInterface; const aOnResult: TOnAsyncRedirectResult = nil); overload;

Define asynchronous execution of interface methods in a background thread
- this method implements any interface via a fake class, which will redirect all methods calls into calls of another interface, but as a FIFO in a background thread, shared with TimerEnable/TimerDisable process
- parameters will be serialized and stored as JSON in the queue
- by design, only procedure methods without any output parameters are allowed, since their execution will take place asynchronously
- of course, a slight delay is introduced in aDestinationInterface methods execution, but the main process thread is not delayed any more, and is free from potential race conditions
- the returned fake aCallbackInterface should be freed before TRest is destroyed, to release the redirection resources
- it is an elegant resolution to the most difficult implementation problem of SOA callbacks, which is to avoid race condition on reentrance, e.g. if a callback is run from a thread, and then the callback code try to execute something in the context of the initial thread, protected by a critical section (mutex)


property BackgroundBatch: TRestBatchLockedDynArray read fBackgroundBatch;

Direct access to the background thread TRestBatch instances


property Name: RawUtf8 read fThreadName;

The identifier of the thread, as logged


property Rest: TRest read fRest;

Direct access to the TRest instance owner


1.3.3. TRestRunThreads

TRestRunThreads = class(TSynPersistentLock)

Access to the Multi-Threading process of a TRest instance


constructor Create(aOwner: TRest); reintroduce;

Initialize the threading process


destructor Destroy; override;

Finalize the threading process


function EnsureBackgroundTimerExists: TRestBackgroundTimer;

Low-level access with optional initialization of the associated timer
- this function is thread-safe


function MultiRedirect(const aGuid: TGuid; out aCallbackInterface; aCallBackUnRegisterNeeded: boolean = true): IMultiCallbackRedirect; overload;

Define redirection of interface methods calls in one or several instances
- this class allows to implements any interface via a fake class, which will redirect all methods calls to one or several other interfaces
- returned aCallbackInterface will redirect all its methods (identified by aGuid) into an internal list handled by IMultiCallbackRedirect.Redirect
- typical use is thefore:

 fSharedCallback: IMyService;
 fSharedCallbacks: IMultiCallbackRedirect;
 ...
   if fSharedCallbacks = nil then
   begin
     fSharedCallbacks := aRest.Run.MultiRedirect(IMyService, fSharedCallback);
     aServices.SubscribeForEvents(fSharedCallback);
   end;
   fSharedCallbacks.Redirect(TMyCallback.Create,[]);
   // now each time fSharedCallback receive one event, all callbacks
   // previously registered via Redirect() will receive it
 ...
   fSharedCallbacks := nil; // will stop redirection
                            // and unregister callbacks, if needed

function NewBackgroundThreadMethod(const Format: RawUtf8; const Args: array of const): TSynBackgroundThreadMethod;

Allows to safely execute a processing method in a background thread
- returns a TSynBackgroundThreadMethod instance, ready to execute any background task via its RunAndWait() method
- will properly call BeginCurrentThread/EndCurrentThread methods
- you should supply some runtime information to name the thread, for proper debugging


function NewBackgroundThreadProcess( const aOnProcess: TOnSynBackgroundThreadProcess; aOnProcessMS: cardinal; const Format: RawUtf8; const Args: array of const; aStats: TSynMonitorClass=nil): TSynBackgroundThreadProcess;

Allows to safely execute a process at a given pace
- returns a TSynBackgroundThreadProcess instance, ready to execute the supplied aOnProcess event in a loop, as aOnProcessMS periodic task
- will properly call BeginCurrentThread/EndCurrentThread methods
- you should supply some runtime information to name the thread, for proper debugging


function NewParallelProcess(ThreadCount: integer; const Format: RawUtf8; const Args: array of const): TSynParallelProcess;

Allows to safely execute a process in parallel
- returns a TSynParallelProcess instance, ready to execute any task in parrallel in a thread-pool given by ThreadCount
- will properly call BeginCurrentThread/EndCurrentThread methods
- you should supply some runtime information to name the thread, for proper debugging


function Once(const aOnProcess: TOnSynBackgroundTimerProcess): boolean;

Execute once a task in the background, without waiting for it


function SystemUseTrack(periodSec: integer = 10): TSystemUse;

Will gather CPU and RAM information in a background thread
- you can specify the update frequency, in seconds
- access to the information via the returned instance, which maps the TSystemUse.Current class function
- do nothing if global TSystemUse.Current was already assigned


function TimerDisable(const aOnProcess: TOnSynBackgroundTimerProcess): boolean;

Undefine a task running on a periodic number of seconds
- should have been registered by a previous call to TimerEnable() method
- returns true on success, false if the supplied task was not registered


function TimerEnable(const aOnProcess: TOnSynBackgroundTimerProcess; aOnProcessSecs: cardinal): TRestBackgroundTimer;

Define a task running on a periodic number of seconds in a background thread
- could be used to run background maintenance or monitoring tasks on this TRest instance, at a low pace (typically every few minutes)
- will instantiate and run a shared TSynBackgroundTimer instance for this TRest, so all tasks will share the very same thread
- you can run BackgroundTimer.EnQueue or ExecuteNow methods to implement a FIFO queue, or force immediate execution of the process
- will call BeginCurrentThread/EndCurrentThread as expected e.g. by logs


procedure AsyncInterning(Interning: TRawUtf8Interning; InterningMaxRefCount: integer = 2; PeriodMinutes: integer = 5);

Allows background garbage collection of specified RawUtf8 interning
- will run Interning.Clean(2) every 5 minutes by default
- set InterningMaxRefCount=0 to disable process of the Interning instance
- note that InterningMaxRefCount and PeriodMinutes parameters (if not 0), are common for all TRawUtf8Interning instances (the latest value wins)
- you may e.g. run the following to clean up TDocVariant interned RawUtf8:

 aRest.Run.AsyncInterning(DocVariantType.InternNames);
 aRest.Run.AsyncInterning(DocVariantType.InternValues);

procedure AsyncRedirect(const aGuid: TGuid; const aDestinationInterface: IInvokable; out aCallbackInterface; const aOnResult: TOnAsyncRedirectResult = nil); overload;

Define asynchronous execution of interface methods in a background thread
- this class allows to implements any interface via a fake class, which will redirect all methods calls into calls of another interface, but as a FIFO in a background thread, shared with TimerEnable/TimerDisable process
- it is an elegant resolution to the most difficult implementation problem of SOA callbacks, which is to avoid race condition on reentrance, e.g. if a callback is run from a thread, and then the callback code try to execute something in the context of the initial thread, protected by a critical section (mutex)
- is a wrapper around BackgroundTimer.AsyncRedirect()


procedure AsyncRedirect(const aGuid: TGuid; const aDestinationInstance: TInterfacedObject; out aCallbackInterface; const aOnResult: TOnAsyncRedirectResult = nil); overload;

Define asynchronous execution of interface methods in a background thread
- this class allows to implements any interface via a fake class, which will redirect all methods calls into calls of another interface, but as a FIFO in a background thread, shared with TimerEnable/TimerDisable process
- it is an elegant resolution to the most difficult implementation problem of SOA callbacks, which is to avoid race condition on reentrance, e.g. if a callback is run from a thread, and then the callback code try to execute something in the context of the initial thread, protected by a critical section (mutex)
- is a wrapper around BackgroundTimer.AsyncRedirect()


procedure BeginCurrentThread(Sender: TThread);

You can call this method in TThread.Execute to ensure that the thread will be taken into account during process
- this method will redirect TRestServer.OnBeginCurrentThread


procedure EndCurrentThread(Sender: TThread);

You can call this method just before a thread is finished to ensure e.g. that the associated external DB connection will be released
- this method will redirect TRestServer.OnEndCurrentThread


procedure Shutdown;

Notify that no new registration is allowed


property BackgroundTimer: TRestBackgroundTimer read fBackgroundTimer;

Low-level access to the associated timer
- may contain nil if EnsureBackgroundTimerExists has not yet been called


1.3.4. ERestException

ERestException = class(ESynException)

Exception class raised on TRest issues


1.3.5. TRest

TRest = class(TInterfaceResolver)

Abstract REpresentational State Transfer (REST) client/server class
- see Orm: IRestOrm, Services: TServiceContainer and Run: TRestRunThreads main properties for its actual REST-oriented process
- in PUREMORMOT2 mode, all direct ORM or threading methods are hidden
- is a TInterfaceResolver so is able to resolve IRestOrm
- do NOT use this abstract class, but one of its fully implemented children


constructor Create(aModel: TOrmModel); virtual;

Initialize the class, and associate it to a specified database Model


constructor RegisteredClassCreateFrom(aModel: TOrmModel; aDefinition: TSynConnectionDefinition; aServerHandleAuthentication: boolean); virtual;

Inherited classes should unserialize the other aDefinition properties by overriding this method, in a reverse logic to overriden DefinitionTo()


destructor Destroy; override;

Release internal used instances
- e.g. release associated TOrmModel and TServiceContainer


class function ClassFrom(aDefinition: TSynConnectionDefinition): TRestClass;

Retrieve the registered class from the aDefinition.Kind string


class function CreateFrom(aModel: TOrmModel; aDefinition: TSynConnectionDefinition; aServerHandleAuthentication: boolean): TRest;

Create a new TRest instance from its Model and stored values
- aDefinition.Kind will define the actual class which will be instantiated: currently TRestServerFullMemory, TRestServerDB, TRestClientUriNamedPipe, TRestClientUriMessage, TRestHttpClientSocket, TRestHttpClientWinINet, TRestHttpClientWinHttp, and TRestHttpClientCurl classes are recognized by this method
- then other aDefinition fields will be used to refine the instance: please refer to each overriden DefinitionTo() method documentation
- use TRestMongoDBCreate() and/or TRestExternalDBCreate() instead to create a TRest instance will all tables defined as external when aDefinition.Kind is 'MongoDB' or a TSqlDBConnectionProperties class
- will raise an exception if the supplied definition are not valid


class function CreateFromFile(aModel: TOrmModel; const aJsonFile: TFileName; aServerHandleAuthentication: boolean; aKey: cardinal = 0): TRest;

Create a new TRest instance from its Model and a JSON file
- aDefinition.Kind will define the actual class which will be instantiated
- you can specify a custom Key, if the default is not safe enough for you


class function CreateFromJson(aModel: TOrmModel; const aJsonDefinition: RawUtf8; aServerHandleAuthentication: boolean; aKey: cardinal = 0): TRest;

Create a new TRest instance from its Model and JSON stored values
- aDefinition.Kind will define the actual class which will be instantiated
- you can specify a custom Key, if the default is not safe enough for you


class function CreateTryFrom(aModel: TOrmModel; aDefinition: TSynConnectionDefinition; aServerHandleAuthentication: boolean): TRest;

Try to create a new TRest instance from its Model and stored values
- will return nil if the supplied definition are not valid
- if the newly created instance is a TRestServer, will force the supplied aServerHandleAuthentication parameter to enable authentication


function DefinitionToJson(Key: cardinal = 0): RawUtf8;

Save the properties into a JSON file
- you can then use TRest.CreateFromJson() to re-instantiate it
- you can specify a custom Key, if the default is not enough for you


function Enter(const TextFmt: RawUtf8; const TextArgs: array of const; aInstance: TObject = nil): ISynLog;

Ease logging of method enter/leave in the context of the current TRest


function GetCurrentSessionUserID: TID; virtual; abstract;

Internal method to retrieve the current Session TAuthUser.ID


function GetServerTimestamp(tix64: Int64): TTimeLog; virtual;

Retrieve the server time stamp
- default implementation will use an internal Offset to compute the value from PC time (i.e. NowUtc+Offset as TTimeLog)
- inherited classes may override this method, or set the appropriate value in Offset field


function NewBackgroundThreadMethod(const Format: RawUtf8; const Args: array of const): TSynBackgroundThreadMethod;

TRestRunThreads compatibility methods


function ServiceContainer: TServiceContainer; virtual; abstract;

Access or initialize the internal IoC resolver, used for interface-based remote services, and more generaly any Services.Resolve() call
- create and initialize the internal TServiceContainer if no service interface has been registered yet
- may be used to inject some dependencies, which are not interface-based remote services, but internal IoC, without the ServiceRegister() or ServiceDefine() methods - e.g.

 aRest.ServiceContainer.InjectResolver([TInfraRepoUserFactory.Create(aRest)], true);

- overriden methods will return TServiceContainerClient or TServiceContainerServer instances, on TRestClient or TRestServer


function TableRowCount(Table: TOrmClass): Int64;

Backward compatibility redirections to the homonymous IRestOrm methods see IRestOrm documentation for the proper use information


procedure DefinitionTo(Definition: TSynConnectionDefinition); virtual;

Save the TRest properties into a persistent storage object
- you can then use TRest.CreateFrom() to re-instantiate it
- current Definition.Key value will be used for the password encryption
- this default implementation will set the class name in Definition.Kind: inherited classes should override this method and serialize other properties, then override RegisteredClassCreateFrom() protected method to initiate the very same instance


procedure DefinitionToFile(const aJsonFile: TFileName; aKey: cardinal = 0);

Save the properties into a JSON file
- you can then use TRest.CreateFromFile() to re-instantiate it
- you can specify a custom Key, if the default is not enough for you


procedure InternalLog(const Format: RawUtf8; const Args: array of const; Level: TSynLogLevel = sllTrace); overload;

Ease logging of some text in the context of the current TRest


procedure InternalLog(const Text: RawUtf8; Level: TSynLogLevel); overload;

Ease logging of some text in the context of the current TRest


procedure ServicesRelease(Caller: TServiceContainer);

Internal procedure called to implement TServiceContainer.Release


procedure SetOrmInstance(aORM: TRestOrmParent); virtual;

Called by TRestOrm.Create overriden constructor to set fOrm from IRestOrm


procedure SetServerTimestamp(const Value: TTimeLog);

Set the server time stamp offset from the given date/time
- if Value is 0, the current local UTC time will be used


property AcquireExecution: TRestAcquireExecutions read fAcquireExecution;

Low-level access to the execution mode of the ORM and SOA process


property AcquireExecutionLockedTimeOut[Cmd: TRestServerUriContextCommand]: cardinal read GetAcquireExecutionLockedTimeOut write SetAcquireExecutionLockedTimeOut;

The time (in milli seconds) to try locking internal commands of this class
- this value is used only for AcquireExecutionMode[*]=amLocked
- by default, TRestServer.Uri() will lock for Write ORM according to AcquireWriteTimeOut (i.e. AcquireExecutionLockedTimeOut[execOrmWrite]) and other operations won't be locked nor have any time out set


property AcquireExecutionMode[Cmd: TRestServerUriContextCommand]: TRestServerAcquireMode read GetAcquireExecutionMode write SetAcquireExecutionMode;

How this class execute its internal commands
- by default, TRestServer.Uri() will lock for Write ORM according to AcquireWriteMode (i.e. AcquireExecutionMode[execOrmWrite]=amLocked) and other operations won't be protected (for better scaling)
- you can tune this behavior by setting this property to the expected execution mode, e.g. execute all method-based services in a dedicated thread via

 aServer.AcquireExecutionMode[execSoaByMethod] := amBackgroundThread;

- if you use external DB and a custom ConnectionTimeOutMinutes value, both read and write access should be locked, so you should set:

 aServer.AcquireExecutionMode[execOrmGet] := am***;
 aServer.AcquireExecutionMode[execOrmWrite] := am***;

here, safe blocking am*** modes are any mode but amUnlocked, i.e. either amLocked, amBackgroundThread, amBackgroundOrmSharedThread or amMainThread


property AcquireWriteMode: TRestServerAcquireMode index execOrmWrite read GetAcquireExecutionMode write SetAcquireExecutionMode;

How this class will handle write access to the database
- is a common wrapper to AcquireExecutionMode[execOrmWrite] property
- default amLocked mode will wait up to AcquireWriteTimeOut milli seconds to have a single access to the server write ORM methods
- amBackgroundThread will execute the write methods in a queue, in a dedicated unique thread (which can be convenient, especially for external database transaction process)
- amBackgroundOrmSharedThread will execute all ORM methods in a queue, in a dedicated unique thread, shared for both execOrmWrite and execOrmGet, but still dedicated for execSoaByMethod and execSoaByInterface
- a slower alternative to amBackgroundThread may be amMainThread
- you can set amUnlocked for a concurrent write access, but be aware that it may lead into multi-thread race condition issues, depending on the database engine used


property AcquireWriteTimeOut: cardinal index execOrmWrite read GetAcquireExecutionLockedTimeOut write SetAcquireExecutionLockedTimeOut;

The time (in milli seconds) which the class will wait for acquiring a write acccess to the database, when AcquireWriteMode is amLocked
- is a common wrapper to AcquireExecutionLockedTimeOut[execOrmWrite]
- in order to handle safe transactions and multi-thread safe writing, the server will identify transactions using the client Session ID: this property will set the time out wait period
- default value is 5000, i.e. TRestServer.Uri will wait up to 5 seconds in order to acquire the right to write on the database before returning a "408 Request Time-out" status error


property LogClass: TSynLogClass read fLogClass write SetLogClass;

Access to the TSynLog class used for logging
- equals TSynLog by default - but you could change it to a custom class


property LogFamily: TSynLogFamily read fLogFamily;

Access to the associate TSynLog class familly


property LogLevel: TSynLogLevels read fLogLevel;

Access to the associate TSynLog class events


property Model: TOrmModel read fModel;

Low-level access to the associated Data Model


property Orm: IRestOrm read fOrm;

Main access to the IRestOrm methods of this instance


property PrivateGarbageCollector: TSynObjectList read fPrivateGarbageCollector;

A local "Garbage collector" list, for some classes instances which must live during the whole TRestServer process
- is used internally by the class, but can be used for business code


property Run: TRestRunThreads read fRun;

Access to the Multi-Threading process of this instance


property Services: TServiceContainer read fServices;

Access to the interface-based services list
- may be nil if no service interface has been registered yet: so be aware that the following line may trigger an access violation if no ICalculator is defined on server side:

 if fServer.Services['Calculator'].Get(Calc)) then
   ...

- safer typical use, following the DI/IoC pattern, and which will not trigger any access violation if Services=nil, could be:

 if fServer.Services.Resolve(ICalculator, Calc) then
   ...

1.3.6. TAuthGroup

TAuthGroup = class(TOrm)

Table containing the available user access rights for authentication
- this class should be added to the TOrmModel, together with TAuthUser, to allow authentication support
- you can inherit from it to add your custom properties to each user info: TOrmModel will search for any class inheriting from TAuthGroup to manage per-group authorization data
- by default, it won't be accessible remotely by anyone


class procedure InitializeTable(const Server: IRestOrmServer; const FieldName: RawUtf8; Options: TOrmInitializeTableOptions); override;

Called when the associated table is created in the database
- on a new database, if TAuthUser and TAuthGroup tables are defined in the associated TOrmModel, it this will add 'Admin', 'Supervisor', and 'User' rows in the AuthUser table (with 'synopse' as default password), and associated 'Admin', 'Supervisor', 'User' and 'Guest' groups, with the following access rights to the AuthGroup table:

            POSTSQL SELECTSQL Service AuthR AuthW TablesR TablesW
 Admin        Yes     Yes       Yes    Yes   Yes    Yes    Yes
 Supervisor   No      Yes       Yes    Yes   No     Yes    Yes
 User         No      No        Yes    No    No     Yes    Yes
 Guest        No      No        No     No    No     Yes    No

- 'Admin' will be the only able to execute remote not SELECT SQL statements for POST commands (reSQL flag in TOrmAccessRights.AllowRemoteExecute) and modify the Auth tables (i.e. AuthUser and AuthGroup)
- 'Admin' and 'Supervisor' will allow any SELECT SQL statements to be executed, even if the table can't be retrieved and checked (corresponding to the reSqlSelectWithoutTable flag)
- 'User' won't have the reSqlSelectWithoutTable flag, nor the right to retrieve the Auth tables data for other users
- 'Guest' won't have access to the interface-based remote JSON-RPC service (no reService flag), nor perform any modification to a table: in short, this is an ORM read-only limited user
- you MUST override the default 'synopse' password to a custom value, or at least customize the global AuthAdminDefaultPassword, AuthSupervisorDefaultPassword, AuthUserDefaultPassword variables
- of course, you can change and tune the settings of the AuthGroup and AuthUser tables, but only 'Admin' group users will be able to remotely modify the content of those two tables


property AccessRights: RawUtf8 index 1600 read fAccessRights write fAccessRights;

A textual representation of a TOrmAccessRights buffer


property Ident: RawUtf8 index 50 read fIdent write fIdent stored AS_UNIQUE;

The access right identifier, ready to be displayed
- the same identifier can be used only once (this column is marked as unique via a "stored AS_UNIQUE" (i.e. "stored false") attribute)
- so you can retrieve a TAuthGroup ID from its identifier, as such:

 UserGroupID := fClient.MainFieldID(TAuthGroup,'User');

property OrmAccessRights: TOrmAccessRights read GetOrmAccessRights write SetOrmAccessRights;

Corresponding TOrmAccessRights for this authentication group
- content is converted into/from text format via AccessRight DB property (so it will be not fixed e.g. by the binary TOrmTableBits layout, i.e. the MAX_TABLES constant value)
- if you want to call Edit on the returned value, use a temp variable:

var
  oar: TOrmAccessRights;
begin
  oar := Group.OrmAccessRights;
  oar.Edit(....);
  oar.Edit(....);
  Group.OrmAccessRights := oar;
  rest.Update(Group);

property SessionTimeout: integer read fSessionTimeOut write fSessionTimeOut;

The number of minutes a session is kept alive


1.3.7. TAuthUser

TAuthUser = class(TOrm)

Table containing the Users registered for authentication
- this class should be added to the TOrmModel, together with TAuthGroup, to allow authentication support
- you can inherit from it to add your custom properties to each user info: TOrmModel will search for any class inheriting from TAuthUser to manage per-user authorization data
- by default, it won't be accessible remotely by anyone; to enhance security, you could use the TSynValidatePassWord filter to this table


function CanUserLog(Ctxt: TObject): boolean; virtual;

Check if the user can authenticate in its current state
- Ctxt is a TRestServerUriContext instance
- called by TRestServerAuthentication.GetUser() method
- this default implementation will return TRUE, i.e. allow the user to log on
- override this method to disable user authentication, e.g. if the user is disabled via a custom ORM boolean and date/time field


class function ComputeHashedPassword(const aPasswordPlain: RawUtf8; const aHashSalt: RawUtf8 = ''; aHashRound: integer = 20000): RawUtf8; virtual;

Static function allowing to compute a hashed password
- as expected by this class
- defined as virtual so that you may use your own hashing class
- you may specify your own values in aHashSalt/aHashRound, to enable Pbkdf2HmacSha256() use instead of plain Sha256(): it will increase security on storage side (reducing brute force attack via rainbow tables)


procedure SetPassword(const aPasswordPlain, aHashSalt: RawUtf8; aHashRound: integer = 20000);

Set the PasswordHashHexa field from a plain password content and salt
- use this method to specify aHashSalt/aHashRound values, enabling Pbkdf2HmacSha256() use instead of plain Sha256(): it will increase security on storage side (reducing brute force attack via rainbow tables)
- you may use an application specific fixed salt, and/or append the user LogonName to make the challenge unique for each TAuthUser
- the default aHashRound=20000 is slow but secure - since the hashing process is expected to be done on client side, you may specify your own higher/slower value, depending on the security level you expect


property Data: RawBlob read fData write fData;

Some custom data, associated to the User
- Server application may store here custom data
- its content is not used by the framework but 'may' be used by your application


property DisplayName: RawUtf8 index 50 read fDisplayName write fDisplayName;

The User Name, as may be displayed or printed


property GroupRights: TAuthGroup read fGroupRights write fGroupRights;

The associated access rights of this user
- access rights are managed by group
- in TAuthSession.User instance, GroupRights property will contain a REAL TAuthGroup instance for fast retrieval in TRestServer.Uri
- note that 'Group' field name is not allowed by SQLite


property LogonName: RawUtf8 index 20 read fLogonName write fLogonName stored AS_UNIQUE;

The User identification Name, as entered at log-in
- the same identifier can be used only once (this column is marked as unique via a "stored AS_UNIQUE" - i.e. "stored false" - attribute), and therefore indexed in the database (e.g. hashed in TRestStorageInMemory)


property PasswordHashHexa: RawUtf8 index 64 read fPasswordHashHexa write fPasswordHashHexa;

The hexa encoded associated SHA-256 hash of the password
- see TAuthUser.ComputeHashedPassword() or SetPassword() methods
- store the SHA-256 32 bytes as 64 hexa chars


property PasswordPlain: RawUtf8 write SetPasswordPlain;

Able to set the PasswordHashHexa field from a plain password content
- in fact, PasswordHashHexa := Sha256('salt'+PasswordPlain) in UTF-8
- use SetPassword() method if you want to customize the hash salt value and use the much safer Pbkdf2HmacSha256 algorithm


1.3.8. TRestServerConnectionOpaque

TRestServerConnectionOpaque = record

An opaque connection-specific pointer identifier with a strong type
- each raw connection instance maintains two abstract PtrUInt tags
- match THttpServerConnectionOpaque as defined in mormot.net.http


ValueExternal: PtrUInt;

Pointer-sized tag free for the end-user code


ValueInternal: PtrUInt;

Pointer-sized tag reserved to mORMot (e.g. to idenfity a REST session)


1.3.9. TRestUriParams

TRestUriParams = object(TObject)

Store all parameters for a Client or Server method call
- as used by TRestServer.Uri or TRestClientUri.InternalUri


InBody: RawUtf8;

Input parameter containing the caller message body
- e.g. some GET/POST/PUT JSON data can be specified here


InHead: RawUtf8;

Input parameter containing the caller message headers
- you can use e.g. to retrieve the remote IP:

 Call.Header(HEADER_REMOTEIP_UPPER)
 or FindNameValue(Call.InHead,HEADER_REMOTEIP_UPPER)

but consider rather using TRestServerUriContext.RemoteIP


LowLevelBearerToken: RawUtf8;

Pre-parsed "Bearer" HTTP header value


LowLevelConnectionFlags: TRestUriParamsLowLevelFlags;

Low-level properties of the current connection


LowLevelConnectionID: TRestConnectionID;

Numerical reference to the connection which made this request
- stores mormot.net.http's THttpServerConnectionID, e.g. a http.sys 64-bit ID, or an incremental rolling sequence of 31-bit integers for THttpServer/TWebSocketServer, or maybe a raw PtrInt(self/THandle)


LowLevelConnectionOpaque: PRestServerConnectionOpaque;

Most HTTP servers support a per-connection pointer storage
- may be nil if unsupported, e.g. by the http.sys servers
- map to THttpAsyncServerConnection or THttpServerSocket fConnectionOpaque of type THttpServerConnectionOpaque as defined in mormot.net.http
- could be used to avoid a lookup to a ConnectionID-indexed dictionary
- warning: only ValueExternal is usable by end-user code


LowLevelRemoteIP: RawUtf8;

Pre-parsed Remote IP of the current connection
- may equal '' if remote IP is the 127.0.0.1 loopback


LowLevelUserAgent: RawUtf8;

Pre-parsed "User-Agent" HTTP header value


Method: RawUtf8;

Input parameter containing the caller method
- handle standard REST codes as GET/POST/PUT/DELETE; but also our own extensions like LOCK/UNLOCK/BEGIN/END/ABORT


OutBody: RawUtf8;

Output parameter to be set to the response message body


OutHead: RawUtf8;

Output parameter to be set to the response message header
- it is the right place to set the returned message body content type, e.g. TEXT_CONTENT_TYPE_HEADER or HTTP_CONTENT_TYPE_HEADER: if not set, the default JSON_CONTENT_TYPE_HEADER will be returned to the client, meaning that the message is JSON
- you can use OutBodyType() function to retrieve the stored content-type


OutInternalState: cardinal;

Output parameter to be set to the database internal state


OutStatus: cardinal;

Output parameter to be set to the HTTP status integer code
- HTTP_NOTFOUND=404 e.g. if the url doesn't start with Model.Root (caller can try another TRestServer)


RestAccessRights: POrmAccessRights;

Associated RESTful access rights
- AccessRights must be handled by the TRestServer child, according to the Application Security Policy (user logging, authentification and rights management) - making access rights a parameter allows this method to be handled as pure stateless, thread-safe and session-free


Url: RawUtf8;

Input parameter containing the caller URI


function Header(UpperName: PAnsiChar): RawUtf8;

Just a wrapper around FindNameValue(InHead,UpperName)
- use e.g. as

 Call.Header(HEADER_REMOTEIP_UPPER) or Call.Header(HEADER_BEARER_UPPER)

- consider rather using TRestServerUriContext.InHeader[] or even dedicated TRestServerUriContext.RemoteIP/AuthenticationBearerToken


function HeaderOnce(var Store: RawUtf8; UpperName: PAnsiChar): RawUtf8;

Wrap FindNameValue(InHead,UpperName) with a cache store


function OutBodyType(GuessJsonIfNoneSet: boolean = True): RawUtf8;

Retrieve the "Content-Type" value from OutHead
- if GuessJsonIfNoneSet is TRUE, returns JSON if none was set in headers


function OutBodyTypeIsJson(GuessJsonIfNoneSet: boolean = True): boolean;

Check if the "Content-Type" value from OutHead is JSON
- if GuessJsonIfNoneSet is TRUE, assume JSON is used


procedure InBodyType(var ContentType: RawUtf8; GuessJsonIfNoneSet: boolean = True);

Retrieve the "Content-Type" value from InHead
- if GuessJsonIfNoneSet is TRUE, returns JSON if none was set in headers


procedure Init; overload;

Initialize the non RawUtf8 values


procedure Init(const aUri, aMethod, aInHead, aInBody: RawUtf8); overload;

Initialize the input values


1.3.10. TRestUriContext

TRestUriContext = class(TObject)

Abstract calling context for any Server-Side REST process
- is inherited e.g. by TRestServerUriContext for TRestServer.Uri processing


function AuthenticationBearerToken: RawUtf8; virtual;

Retrieve the "Authorization: Bearer <token>" value from incoming HTTP headers
- typically returns a JWT for statelesss self-contained authentication, as expected by TJwtAbstract.Verify method


function AuthenticationCheck(jwt: TJwtAbstract): boolean; virtual;

Validate "Authorization: Bearer <JWT>" content from incoming HTTP headers
- returns true on success, storing the payload in JwtContent^ field
- set JwtContent^.result = jwtNoToken if jwt is nil
- on failure (i.e. returns false), will set the error context as 403 HTTP_FORBIDDEN so that you may directly write:

 procedure TMyDaemon.Files(Ctxt: TRestServerUriContext);
 begin
   if Ctxt.AuthenticationCheck(fJWT) then
     Ctxt.ReturnFileFromFolder('c:\datafolder');
 end;

function ClientKind: TRestClientKind;

Identify which kind of client is actually connected
- the "User-Agent" HTTP will be checked for 'mORMot' substring, and set ckFramework on match
- either ckAjax for a classic (AJAX) browser, or any other kind of HTTP client
- will be used e.g. by ClientOrmOptions to check if the current remote client expects standard JSON in all cases


function ContentTypeIsJson: boolean;

Check if the content-type input is 'application/json' or ''


function InputAsMultiPart(var MultiPart: TMultiPartDynArray): boolean;

Decode any multipart/form-data POST request input
- returns TRUE and set MultiPart array as expected, on success


function RemoteIPNotLocal: PUtf8Char;

"RemoteIP" value from Call^.LowLevelRemoteIP but nil for '127.0.0.1'
- won't scan the incoming HTTP headers, but it is usually not needed


function TickCount64: Int64;

Low-level wrapper method around GetTickCount64 to cache the value
- may avoid OS API calls on server side, during a request process
- warning: do not use within loops for timeout, because it won't change


procedure Error(const Format: RawUtf8; const Args: array of const; Status: integer = HTTP_BADREQUEST; CacheControlMaxAgeSec: integer = 0); overload;

Use this method to send back an error to the caller
- implementation is just a wrapper over Error(FormatUtf8(Format,Args))


procedure Error(const ErrorMessage: RawUtf8 = ''; Status: integer = HTTP_BADREQUEST; CacheControlMaxAgeSec: integer = 0); overload; virtual;

Use this method to send back an error to the caller
- expects Status to not be HTTP_SUCCESS neither HTTP_CREATED, and will send back a JSON error message to the caller, with the supplied error text
- set CacheControlMaxAgeSec<>0 to include a Cache-Control: max-age = xxx header
- if no ErrorMessage is specified, will return a default text corresponding to the Status code


procedure Error(E: Exception; const Format: RawUtf8; const Args: array of const; Status: integer = HTTP_BADREQUEST); overload; virtual;

Use this method to send back an error to the caller
- will serialize the supplied exception, with an optional error message


procedure OutHeadFromCookie; virtual;

Low-level HTTP header merge of the OutSetCookie value


procedure Redirect(const NewLocation: RawUtf8; PermanentChange: boolean = false);

Use this method notify the caller that the resource URI has changed
- returns a HTTP_TEMPORARYREDIRECT status with the specified location, or HTTP_MOVEDPERMANENTLY if PermanentChange is TRUE


procedure Results(const Values: array of const; Status: integer = HTTP_SUCCESS; Handle304NotModified: boolean = false; CacheControlMaxAgeSec: integer = 0);

Use this method to send back a JSON object with a "result" field
- this method will encode the supplied values as a {"result":"...} JSON object, as such for one value:

 {"result":"OneValue"}

(with one value, you can just call TRestClientUri.CallBackGetResult method to call and decode this value) or as a JSON object containing an array of values:

 {"result":["One","two"]}

- expects Status to be either HTTP_SUCCESS or HTTP_CREATED
- caller can set Handle304NotModified=TRUE for Status=HTTP_SUCCESS and/or set CacheControlMaxAgeSec<>0 to include a Cache-Control: max-age=xxx header


procedure ReturnBlob(const Blob: RawByteString; Status: integer = HTTP_SUCCESS; Handle304NotModified: boolean = true; const FileName: TFileName = ''; CacheControlMaxAgeSec: integer = 0);

Uses this method to send back directly any binary content to the caller
- the exact MIME type will be retrieved using GetMimeContentTypeHeader(), from the supplied Blob binary buffer, and optional a file name
- by default, the HTTP_NOTMODIFIED process will take place, to minimize bandwidth between the server and the client
- set CacheControlMaxAgeSec<>0 to include a Cache-Control: max-age=xxx header


procedure ReturnFile(const FileName: TFileName; Handle304NotModified: boolean = false; const ContentType: RawUtf8 = ''; const AttachmentFileName: RawUtf8 = ''; const Error404Redirect: RawUtf8 = ''; CacheControlMaxAgeSec: integer = 0);

Use this method to send back a file to the caller
- this method will let the HTTP server return the file content
- if Handle304NotModified is TRUE, will check the file age to ensure that the file content will be sent back to the server only if it changed; set CacheControlMaxAgeSec<>0 to include a Cache-Control: max-age=xxx header
- if ContentType is left to default '', method will guess the expected mime-type from the file name extension
- if the file name does not exist, a generic 404 error page will be returned, unless an explicit redirection is defined in Error404Redirect
- you can also specify the resulting file name, as downloaded and written by the client browser, in the optional AttachmentFileName parameter, if the URI does not match the expected file name


procedure ReturnFileFromFolder(const FolderName: TFileName; Handle304NotModified: boolean = true; const DefaultFileName: TFileName = 'index.html'; const Error404Redirect: RawUtf8 = ''; CacheControlMaxAgeSec: integer = 0); virtual;

Use this method to send back a file from a local folder to the caller
- this method will let the HTTP server return the file content
- if Handle304NotModified is TRUE, will check the file age to ensure that the file content will be sent back to the server only if it changed set CacheControlMaxAgeSec<>0 to include a Cache-Control: max-age=xxx header


procedure Returns(const result: RawUtf8; Status: integer = HTTP_SUCCESS; const CustomHeader: RawUtf8 = ''; Handle304NotModified: boolean = false; HandleErrorAsRegularResult: boolean = false; CacheControlMaxAgeSec: integer = 0; const ServerHash: RawUtf8 = ''); overload;

Use this method to send back directly a result value to the caller
- expects Status to be either HTTP_SUCCESS, HTTP_NOTMODIFIED, HTTP_CREATED, or HTTP_TEMPORARYREDIRECT, and will return as answer the supplied result content with no transformation
- if Status is an error code, it will call Error() method
- CustomHeader optional parameter can be set e.g. to TEXT_CONTENT_TYPE_HEADER if the default JSON_CONTENT_TYPE is not OK, or calling GetMimeContentTypeHeader() on the returned binary buffer
- if Handle304NotModified is TRUE and Status is HTTP_SUCCESS, the result content will be hashed (using crc32c) and in case of no modification will return HTTP_NOTMODIFIED to the browser, without the actual result content (to save bandwidth)
- set CacheControlMaxAgeSec<>0 to include a Cache-Control: max-age=xxx header


procedure Returns(const NameValuePairs: array of const; Status: integer = HTTP_SUCCESS; Handle304NotModified: boolean = false; HandleErrorAsRegularResult: boolean = false; const CustomHeader: RawUtf8 = ''); overload;

Use this method to send back a JSON object to the caller
- this method will encode the supplied values e.g. as

 JsonEncode(['name','John','year',1972]) = '{"name":"John","year":1972}'

- implementation is just a wrapper around Returns(JsonEncode([]))
- note that cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be transmitted, therefore wrongly)
- expects Status to be either HTTP_SUCCESS or HTTP_CREATED
- caller can set Handle304NotModified=TRUE for Status=HTTP_SUCCESS


procedure Returns(Value: TObject; Status: integer = HTTP_SUCCESS; Handle304NotModified: boolean = false; OrmOptions: TOrmWriterOptions = []; const CustomHeader: RawUtf8 = ''); overload;

Use this method to send back any object as JSON document to the caller
- this method will call ObjectToJson() to compute the returned content
- you can customize OrmOptions, to force the returned JSON object to have its TOrm nested fields serialized as true JSON arrays or objects, or add an "ID_str" string field for JavaScript


procedure ReturnsJson(const Value: variant; Status: integer = HTTP_SUCCESS; Handle304NotModified: boolean = false; Escape: TTextWriterKind = twJsonEscape; MakeHumanReadable: boolean = false; const CustomHeader: RawUtf8 = ''; HandleErrorAsRegularResult: boolean = false);

Use this method to send back any variant as JSON to the caller
- this method will call VariantSaveJson() to compute the returned content


procedure SetRemoteIP(var IP: RawUtf8);

Retrieve the "RemoteIP" value from Call^.LowLevelRemoteIP or from the incoming HTTP headers
- may return '127.0.0.1'


procedure Success(Status: integer = HTTP_SUCCESS); virtual;

Use this method if the caller expect no data, just a status
- just wrap the overloaded Returns() method with no result value
- if Status is an error code, it will call Error() method
- by default, calling this method will mark process as successful


property Call: PRestUriParams read fCall;

Access to all input/output parameters at TRestServer.Uri() level
- process should better call Results() or Success() methods to set the appropriate answer or Error() method in case of an error
- low-level access to the call parameters can be made via this pointer


property InCookie[CookieName: RawUtf8]: RawUtf8 read GetInCookie write SetInCookie;

Retrieve an incoming HTTP cookie value
- cookie name are case-sensitive


property InHeader[const HeaderName: RawUtf8]: RawUtf8 read GetInHeader;

Retrieve an incoming HTTP header
- the supplied header name is case-insensitive
- but rather call RemoteIP or UserAgent properties instead of InHeader['remoteip'] or InHeader['User-Agent']


property JwtContent: PJwtContent read fJwtContent;

JWT validation information, as filled by AuthenticationCheck()
- equals nil if no JWT authentication was made


property Method: TUriMethod read fMethod;

The used Client-Server method (matching the corresponding HTTP Verb)
- this property will be set from incoming URI, even if RESTful authentication is not enabled


property OutSetCookie: RawUtf8 read fOutSetCookie write SetOutSetCookie;

Define a new 'name=value' cookie to be returned to the client
- if not void, TRestServer.Uri() will define a new 'set-cookie: ...' header in Call^.OutHead
- you can use COOKIE_EXPIRED as value to delete a cookie in the browser
- if no Path=/.. is included, it will append

 '; Path=/'+Server.Model.Root+'; HttpOnly'

property UserAgent: RawUtf8 read GetUserAgent;

Retrieve the "User-Agent" value from the incoming HTTP headers


1.3.11. TRestThread

TRestThread = class(TThreadAbstract)

A simple TThread for doing some process within the context of a REST instance
- inherited classes should override InternalExecute abstract method


constructor Create(aRest: TRest; aOwnRest, aCreateSuspended: boolean);

Initialize the thread
- if aOwnRest is TRUE, the supplied REST instance will be owned by this thread


destructor Destroy; override;

Finalize the thread
- and the associated REST instance if OwnRest is TRUE


function SleepOrTerminated(MS: integer): boolean;

Safe version of Sleep() which won't break the thread process
- returns TRUE if the thread was Terminated
- returns FALSE if successfully waited up to MS milliseconds


procedure TerminatedSet; override;

Properly terminate the thread, notifying WaitForNotExecuting


procedure WaitForNotExecuting(maxMS: integer = 500);

Wait for Execute to be ended (i.e. fExecuting=false)
- will use the internal TEvent so that Terminate will stop it ASAP


property Event: TSynEvent read fEvent;

A event associated to this thread
- used mainly by Terminate/WaitForNotExecuting but could be used for other notification purpose


property Executing: boolean read fExecuting;

Publishes the thread executing state (set when Execute leaves)


property Log: TSynLog read fLog;

Read-only access to the REST TSynLog instance matching this thread
- can be used safely within InternalExecute code


property OwnRest: boolean read fOwnRest;

TRUE if the associated REST instance will be owned by this thread


property Rest: TRest read fRest;

Read-only access to the associated REST instance


property Safe: TSynLocker read fSafe;

A critical section is associated to this thread
- could be used to protect shared resources within the internal process


1.3.12. TOrmModification

TOrmModification = class(TOrm)

Common ancestor for tracking TOrm modifications
- e.g. TOrmHistory and TOrmVersion will inherit from this class to track TOrm changes


function ModifiedID: TID;

Returns the modified record ID, as stored in ModifiedRecord


function ModifiedTable(Model: TOrmModel): TOrmClass;

Returns the modified record table, as stored in ModifiedRecord


function ModifiedTableIndex: integer;

Returns the record table index in the TOrmModel, as stored in ModifiedRecord


property ModifiedRecord: TID read fModifiedRecord write fModifiedRecord;

Identifies the modified record
- ID and table index in TOrmModel is stored as one RecordRef integer
- you can use ModifiedTable/ModifiedID to retrieve the TOrm item
- in case of the record deletion, all matching TOrmHistory won't be touched by TRestOrmServer.AfterDeleteForceCoherency(): so this property is a plain TID/Int64, not a TRecordReference field


property Timestamp: TModTime read fTimestamp write fTimestamp;

When the modification was recorded
- even if in most cases, this timestamp may be synchronized over TRest instances (thanks to TRestClientUri.ServerTimestampSynchronize), it is not safe to use this field as absolute: you should rather rely on pure monotonic ID/RowID increasing values (see e.g. TOrmVersion)


1.3.13. TOrmHistory

TOrmHistory = class(TOrmModification)

Common ancestor for tracking changes on TOrm tables
- used by TRestServer.TrackChanges() method for simple fields history
- TRestServer.InternalUpdateEvent will use this table to store individual row changes as SentDataJson, then will compress them in History BLOB
- note that any layout change of the tracked TOrm table (e.g. adding a new property) will break the internal data format, so will void the table


constructor CreateHistory(const aClient: IRestOrm; aTable: TOrmClass; aID: TID);

Load the change history of a given record
- then you can use HistoryGetLast, HistoryCount or HistoryGet() to access all previous stored versions


destructor Destroy; override;

Finalize any internal memory


function HistoryCount: integer;

Returns how many revisions are stored in the History BLOB
- HistoryOpen() or CreateHistory() should have been called before
- this method will ignore any previous HistoryAdd() call


function HistoryGet(Index: integer; out Event: TOrmHistoryEvent; out Timestamp: TModTime; Rec: TOrm): boolean; overload;

Retrieve an historical version
- HistoryOpen() or CreateHistory() should have been called before
- this method will ignore any previous HistoryAdd() call
- if Rec=nil, will only retrieve Event and Timestamp
- if Rec is set, will fill all simple properties of this TOrm


function HistoryGet(Index: integer): TOrm; overload;

Retrieve an historical version
- HistoryOpen() or CreateHistory() should have been called before
- this method will ignore any previous HistoryAdd() call
- will return either nil, or a TOrm with all simple properties set


function HistoryGet(Index: integer; Rec: TOrm): boolean; overload;

Retrieve an historical version
- HistoryOpen() or CreateHistory() should have been called before
- this method will ignore any previous HistoryAdd() call
- will fill all simple properties of the supplied TOrm instance


function HistoryGetLast(Rec: TOrm): boolean; overload;

Retrieve the latest stored historical version
- HistoryOpen() or CreateHistory() should have been called before
- this method will ignore any previous HistoryAdd() call
- you should not have to use it, since a TRest.Retrieve() is faster


function HistoryGetLast: TOrm; overload;

Retrieve the latest stored historical version
- HistoryOpen() or CreateHistory() should have been called before, otherwise it will return nil
- this method will ignore any previous HistoryAdd() call
- you should not have to use it, since a TRest.Retrieve() is faster


function HistoryOpen(Model: TOrmModel): boolean;

Prepare to access the History BLOB content
- ModifiedRecord should have been set to a proper value
- returns FALSE if the History BLOB is incorrect (e.g. TOrm layout changed): caller shall flush all previous history


function HistorySave(const Server: IRestOrmServer; LastRec: TOrm = nil): boolean;

Update the History BLOB field content
- HistoryOpen() should have been called before using this method - CreateHistory() won't allow history modification
- if HistoryAdd() has not been used, returns false
- ID field should have been set for proper persistence on Server
- otherwise compress the data into History BLOB, deleting the oldest versions if resulting size is biggger than expected, and returns true
- if Server is set, write save the History BLOB to database
- if Server and LastRec are set, its content will be compared with the current record in DB (via a Retrieve() call) and stored: it will allow to circumvent any issue about inconsistent use of tracking, e.g. if the database has been modified directly, by-passing the ORM


procedure HistoryAdd(Rec: TOrm; Hist: TOrmHistory);

Add a record content to the History BLOB
- HistoryOpen() should have been called before using this method - CreateHistory() won't allow history modification
- use then HistorySave() to compress and replace the History field


class procedure InitializeFields(const Fields: array of const; var Json: RawUtf8); virtual;

Override this to customize fields intialization


class procedure InitializeTable(const Server: IRestOrmServer; const FieldName: RawUtf8; Options: TOrmInitializeTableOptions); override;

Called when the associated table is created in the database
- create index on History(ModifiedRecord,Event) for process speed-up


property Event: TOrmHistoryEvent read fEvent write fEvent;

The kind of modification stored
- is heArchiveBlob when this record stores the compress BLOB in History
- otherwise, SentDataJson may contain the latest values as JSON


property History: RawBlob read fHistory write fHistory;

After some events are written as individual SentData content, they will be gathered and compressed within one BLOB field
- use HistoryOpen/HistoryCount/HistoryGet to access the stored data after a call to CreateHistory() constructor
- as any BLOB field, this one won't be retrieved by default: use explicitly TRest.RetrieveBlobFields(aRecordHistory) to get it if you want to access it directly, and not via CreateHistory()


property SentDataJson: RawUtf8 index 4000 read fSentData write fSentData;

For heAdd/heUpdate, the data is stored as JSON
- note that we defined a default maximum size of 4KB for this column, to avoid using a CLOB here - perhaps it may not be enough for huge records - feedback is welcome...


1.3.14. TOrmTableDeleted

TOrmTableDeleted = class(TOrm)

ORM table used to store the deleted items of a versioned table
- the ID/RowID primary key of this table will be the version number (i.e. value computed by TRestServer.InternalRecordVersionCompute), mapped with the corresponding 'TableIndex shl 58' (so that e.g. TRestServer.RecordVersionSynchronizeToBatch() could easily ask for the deleted rows of a given table with a single WHERE clause on the ID/RowID)


property Deleted: Int64 read fDeleted write fDeleted;

This Deleted published field will track the deleted row
- defined as Int64 and not TID, to avoid the generation of the index on this column, which is not needed here (all requests are about ID/RowID)


1.4. Types implemented in the mormot.rest.core unit

1.4.1. PRestServerConnectionOpaque

PRestServerConnectionOpaque = ^TRestServerConnectionOpaque;

Reference to an opaque connection-specific pointer identifier
- may be nil if unsupported, e.g. by the http.sys servers


1.4.2. PRestUriParams

PRestUriParams = ^TRestUriParams;

Used to map set of parameters for a Client or Server method call


1.4.3. TAuthGroupClass

TAuthGroupClass = class of TAuthGroup;

Class-reference type (metaclass) of the table containing the available user access rights for authentication, defined as a group


1.4.4. TAuthUserClass

TAuthUserClass = class of TAuthUser;

Class-reference type (metaclass) of a table containing the Users registered for authentication
- see also TRestServer.OnAuthenticationUserRetrieve custom event


1.4.5. TLibraryRequest

TLibraryRequest = function( Url, Method, SendData: PUtf8Char; UrlLen, MethodLen, SendDataLen: cardinal; out HeadRespFree: TLibraryRequestFree; var Head: PUtf8Char; var HeadLen: cardinal; out Resp: PUtf8Char; out RespLen, State: cardinal): cardinal; cdecl;

The function signature of the LibraryRequest() function
- as exported by TRestServer.ExportServerGlobalLibraryRequest
- and as consummed by TRestClientLibraryRequest on client side


1.4.6. TLibraryRequestFree

TLibraryRequestFree = procedure(Data: pointer); cdecl;

How a TLibraryRequest function will release its Head and Resp returned values


1.4.7. TOnAsyncRedirectResult

TOnAsyncRedirectResult = procedure(const aMethod: TInterfaceMethod; const aInstance: IInvokable; const aParams, aResult: RawUtf8) of object;

Optionally called after TRest.AsyncRedirect background execution
- to retrieve any output result value, as JSON-encoded content
- as used in TRestBackgroundTimer.AsyncBackgroundExecute protected method


1.4.8. TOrmHistoryClass

TOrmHistoryClass = class of TOrmHistory;

Class-reference type (metaclass) to specify the storage table to be used for tracking TOrm changes
- you can create your custom type from TOrmHistory, even for a particular table, to split the tracked changes storage in several tables:

 type
  TOrmMyHistory = class(TOrmHistory);

- as expected by TRestServer.TrackChanges() method


1.4.9. TOrmTableDeletedClass

TOrmTableDeletedClass = class of TOrmTableDeleted;

Class-reference type (metaclass) to specify the storage table to be used for tracking TOrm deletion


1.4.10. TRestAcquireExecutions

TRestAcquireExecutions = array[TRestServerUriContextCommand] of TRestAcquireExecution;

Define how a TRest class may execute its ORM and SOA operations


1.4.11. TRestClass

TRestClass = class of TRest;

Class-reference type (metaclass) of a TRest kind


1.4.12. TRestClientKind

TRestClientKind = ( ckUnknown, ckFramework, ckAJAX );

Used by TRestUriContext.ClientKind to identify the currently connected client


1.4.13. TRestConnectionID

TRestConnectionID = Int64;

A genuine identifier for a given client connection on server side
- see also THttpServerConnectionID as defined in mormot.net.http: may map the http.sys ID, or a genuine 31-bit value from increasing sequence


1.4.14. TRestDynArray

TRestDynArray = array of TRest;

A dynamic array of TRest instances


1.4.15. TRestObjArray

TRestObjArray = array of TRest;

A dynamic array of TRest instances, owning the instances


1.4.16. TRestServerAcquireMode

TRestServerAcquireMode = ( amUnlocked, amLocked, amBackgroundThread, amBackgroundOrmSharedThread, amMainThread );

How a TRest class may execute read or write operations
- used e.g. for TRestServer.AcquireWriteMode or TRestServer.AcquireExecutionMode/AcquireExecutionLockedTimeOut


1.4.17. TRestServerUriContextCommand

TRestServerUriContextCommand = ( execNone, execSoaByMethod, execSoaByInterface, execOrmGet, execOrmWrite );

All commands which may be executed by TRestServer.Uri() method
- execSoaByMethod for method-based services
- execSoaByInterface for interface-based services
- execOrmGet for ORM reads i.e. Retrieve*() methods
- execOrmWrite for ORM writes i.e. Add Update Delete TransactionBegin Commit Rollback methods


1.4.18. TRestUriParamsLowLevelFlag

TRestUriParamsLowLevelFlag = ( llfHttps, llfSecured, llfWebsockets, llfInProcess, llfConnectionUpgrade, llfAuthorized, llfHttp10 );

Flags which may be set by the caller to notify low-level context
- llfHttps is set if the communication was made over HTTPS
- llfSecured if the transmission is encrypted or in-process using e.g. HTTPS/TLS or our proprietary AES/ECDHE WebSockets algorithms
- llfWebsockets if communication was made using WebSockets
- llfInProcess when run from the same process, i.e. on server side
- llfConnectionUpgrade when "connection: upgrade" is within headers
- llfAuthorized when a valid "authorization:" header is set
- llfHttp10 if the connection is of old HTTP/1.0 level
- should exactly match THttpServerRequestFlag from mormot.net.http.pas


1.4.19. TRestUriParamsLowLevelFlags

TRestUriParamsLowLevelFlags = set of TRestUriParamsLowLevelFlag;

Some flags set by the caller to notify low-level context


1.4.20. TSqlAuthUser

TSqlAuthUser = TAuthUser;

Backward compatibility types redirections


1.4.21. TSqlRest

TSqlRest = TRest;

Backward compatibility types redirections


1.4.22. TSqlRestServerUriContextCommand

TSqlRestServerUriContextCommand = TRestServerUriContextCommand;

Backward compatibility types redirections


1.4.23. TSqlRestThread

TSqlRestThread = TRestThread;

Backward compatibility types redirections


1.4.24. TUriMethod

TUriMethod = ( mNone, mGET, mPOST, mPUT, mDELETE, mHEAD, mBEGIN, mEND, mABORT, mLOCK, mUNLOCK, mSTATE, mPATCH, mOPTIONS );

The available HTTP methods transmitted between client and server
- remote ORM supports non-standard mLOCK/mUNLOCK/mABORT/mSTATE verbs
- not all IANA verbs are available, because TRestRouter will only support mGET .. mOPTIONS verbs anyway
- for basic CRUD operations, we consider Create=mPOST, Read=mGET, Update=mPUT and Delete=mDELETE - even if it is not fully RESTful


1.4.25. TUriMethods

TUriMethods = set of TUriMethod;

Set of available HTTP methods transmitted between client and server


1.5. Constants implemented in the mormot.rest.core unit

1.5.1. COOKIE_EXPIRED

COOKIE_EXPIRED = '; Expires=Sat, 01 Jan 2010 00:00:01 GMT';

You can use this cookie value to delete a cookie on the browser side


1.5.2. DEFAULT_HASH_SYNOPSE

DEFAULT_HASH_SYNOPSE = '67aeea294e1cb515236fd7829c55ec820ef888e8e221814d24d83b3dc4d825dd';

Default hashed password set by TAuthGroup.InitializeTable for all users
- contains TAuthUser.ComputeHashedPassword('synopse')
- override AuthAdminDefaultPassword, AuthSupervisorDefaultPassword and AuthUserDefaultPassword values to follow your own application expectations


1.5.3. MAX_SIZE_RESPONSE_LOG

MAX_SIZE_RESPONSE_LOG = 2 shl 10;

Size in bytes, to log up to 2 KB of JSON response, to save space


1.5.4. SERVICE_CONTRACT_NONE_EXPECTED

SERVICE_CONTRACT_NONE_EXPECTED = '*';

Custom contract value to ignore contract validation from client side
- you could set the aContractExpected parameter to this value for TRestClientUri.ServiceDefine or TRestClientUri.ServiceRegister so that the contract won't be checked with the server
- it will be used e.g. if the remote server is not a mORMot server, but a plain REST/HTTP server - e.g. for public API notifications


1.6. Functions or procedures implemented in the mormot.rest.core unit

Functions or proceduresDescription
ToMethodConvert a string HTTP verb into its TUriMethod enumerate
ToTextConvert a TUriMethod enumerate to its #0 terminated uppercase text

1.6.1. ToMethod

function ToMethod(const method: RawUtf8): TUriMethod;

Convert a string HTTP verb into its TUriMethod enumerate
- conversion is case-insensitive


1.6.2. ToText

function ToText(m: TUriMethod): PUtf8Char; overload;

Convert a TUriMethod enumerate to its #0 terminated uppercase text


1.7. Variables implemented in the mormot.rest.core unit

1.7.1. AuthAdminDefaultPassword

AuthAdminDefaultPassword: RawUtf8 = DEFAULT_HASH_SYNOPSE;

Default hashed password set by TAuthGroup.InitializeTable for 'Admin' user
- you can override this value to follow your own application expectations


1.7.2. AuthAdminGroupDefaultTimeout

AuthAdminGroupDefaultTimeout: integer = 10;

Default timeout period set by TAuthGroup.InitializeTable for 'Admin' group
- you can override this value to follow your own application expectations


1.7.3. AuthGuestGroupDefaultTimeout

AuthGuestGroupDefaultTimeout: integer = 60;

Default timeout period set by TAuthGroup.InitializeTable for 'Guest' group
- you can override this value to follow your own application expectations
- note that clients will maintain the session alive using CacheFlush/_ping_


1.7.4. AuthSupervisorDefaultPassword

AuthSupervisorDefaultPassword: RawUtf8 = DEFAULT_HASH_SYNOPSE;

Default hashed password set by TAuthGroup.InitializeTable for 'Supervisor' user
- you can override this value to follow your own application expectations


1.7.5. AuthSupervisorGroupDefaultTimeout

AuthSupervisorGroupDefaultTimeout: integer = 60;

Default timeout period set by TAuthGroup.InitializeTable for 'Supervisor' group
- you can override this value to follow your own application expectations
- note that clients will maintain the session alive using CacheFlush/_ping_


1.7.6. AuthUserDefaultPassword

AuthUserDefaultPassword: RawUtf8 = DEFAULT_HASH_SYNOPSE;

Default hashed password set by TAuthGroup.InitializeTable for 'User' user
- you can override this value to follow your own application expectations


1.7.7. AuthUserGroupDefaultTimeout

AuthUserGroupDefaultTimeout: integer = 60;

Default timeout period set by TAuthGroup.InitializeTable for 'User' group
- you can override this value to follow your own application expectations
- note that clients will maintain the session alive using CacheFlush/_ping_