
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
| Unit Name | Description | |
|---|---|---|
| mormot.core.base | Framework Core Shared Types and RTL-like Functions | |
| mormot.core.buffers | Framework Core Low-Level Memory Buffer Process | |
| mormot.core.data | Framework Core Low-Level Data Processing Functions | |
| mormot.core.datetime | Framework Core Low-Level Date and Time Support | |
| mormot.core.interfaces | Framework Core Low-Level Interface/SOLID Processing | |
| mormot.core.json | Framework Core Low-Level JSON Processing | |
| mormot.core.log | Framework Core Logging | |
| mormot.core.os | Framework Core Low-Level Wrappers to the Operating-System API | |
| mormot.core.perf | Framework Core Performance and Monitoring Classes | |
| mormot.core.rtti | Framework Core Low-Level Cross-Compiler RTTI Definitions | |
| mormot.core.text | Framework Core Low-Level Text Processing | |
| mormot.core.threads | Framework Core Multi-Threading Support | |
| mormot.core.unicode | Framework Core Low-Level Unicode UTF-8 UTF-16 Ansi Conversion | |
| mormot.core.variants | Framework Core Low-Level Variants / TDocVariant process | |
| mormot.crypt.core | Framework Core Cryptographic Process (Hashing and Cypher) | |
| mormot.crypt.jwt | Framework Core JSON Web Tokens (JWT) Support | |
| mormot.crypt.secure | Framework Core Authentication and Security Features | |
| mormot.db.core | Database Framework Core Types and Classes | |
| mormot.orm.base | Object-Relational-Mapping (ORM) Low-Level Process | |
| mormot.orm.core | Object-Relational-Mapping (ORM) Main Types and Classes | |
| mormot.soa.core | Interface-based SOA Process Core Types and Classes |
| Objects | Description | |
|---|---|---|
| ERestException | Exception class raised on TRest issues | |
| TAuthGroup | Table containing the available user access rights for authentication | |
| TAuthUser | Table containing the Users registered for authentication | |
| TOrmHistory | Common ancestor for tracking changes on TOrm tables | |
| TOrmModification | Common ancestor for tracking TOrm modifications | |
| TOrmTableDeleted | ORM table used to store the deleted items of a versioned table | |
| TRest | Abstract REpresentational State Transfer (REST) client/server class | |
| TRestAcquireExecution | Used to store the execution parameters for a TRest instance | |
| TRestBackgroundTimer | TThread able to run one or several tasks at a periodic pace, or do asynchronous interface or batch execution, with proper TRest integration | |
| TRestRunThreads | Access to the Multi-Threading process of a TRest instance | |
| TRestServerConnectionOpaque | An opaque connection-specific pointer identifier with a strong type | |
| TRestThread | A simple TThread for doing some process within the context of a REST instance | |
| TRestUriContext | Abstract calling context for any Server-Side REST process | |
| TRestUriParams | Store all parameters for a Client or Server method call |
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
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
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
ERestException = class(ESynException)
Exception class raised on TRest issues
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 ...
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
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
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)
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
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
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
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)
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...
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)
PRestServerConnectionOpaque = ^TRestServerConnectionOpaque;
Reference to an opaque connection-specific pointer identifier
- may be nil if unsupported, e.g. by the http.sys servers
PRestUriParams = ^TRestUriParams;
Used to map set of parameters for a Client or Server method call
TAuthGroupClass = class of TAuthGroup;
Class-reference type (metaclass) of the table containing the available user access rights for authentication, defined as a group
TAuthUserClass = class of TAuthUser;
Class-reference type (metaclass) of a table containing the Users registered for authentication
- see also TRestServer.OnAuthenticationUserRetrieve custom event
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
TLibraryRequestFree = procedure(Data: pointer); cdecl;
How a TLibraryRequest function will release its Head and Resp returned values
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
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
TOrmTableDeletedClass = class of TOrmTableDeleted;
Class-reference type (metaclass) to specify the storage table to be used for tracking TOrm deletion
TRestAcquireExecutions = array[TRestServerUriContextCommand] of TRestAcquireExecution;
Define how a TRest class may execute its ORM and SOA operations
TRestClass = class of TRest;
Class-reference type (metaclass) of a TRest kind
TRestClientKind = ( ckUnknown, ckFramework, ckAJAX );
Used by TRestUriContext.ClientKind to identify the currently connected client
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
TRestDynArray = array of TRest;
A dynamic array of TRest instances
TRestObjArray = array of TRest;
A dynamic array of TRest instances, owning the instances
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
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
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
TRestUriParamsLowLevelFlags = set of TRestUriParamsLowLevelFlag;
Some flags set by the caller to notify low-level context
TSqlAuthUser = TAuthUser;
Backward compatibility types redirections
TSqlRest = TRest;
Backward compatibility types redirections
TSqlRestServerUriContextCommand = TRestServerUriContextCommand;
Backward compatibility types redirections
TSqlRestThread = TRestThread;
Backward compatibility types redirections
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
TUriMethods = set of TUriMethod;
Set of available HTTP methods transmitted between client and server
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
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
MAX_SIZE_RESPONSE_LOG = 2 shl 10;
Size in bytes, to log up to 2 KB of JSON response, to save space
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
| Functions or procedures | Description | |
|---|---|---|
| ToMethod | Convert a string HTTP verb into its TUriMethod enumerate | |
| ToText | Convert a TUriMethod enumerate to its #0 terminated uppercase text |
function ToMethod(const method: RawUtf8): TUriMethod;
Convert a string HTTP verb into its TUriMethod enumerate
- conversion is case-insensitive
function ToText(m: TUriMethod): PUtf8Char; overload;
Convert a TUriMethod enumerate to its #0 terminated uppercase text
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
AuthAdminGroupDefaultTimeout: integer = 10;
Default timeout period set by TAuthGroup.InitializeTable for 'Admin' group
- you can override this value to follow your own application expectations
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_
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
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_
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
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_