The standard RESTful methods are implemented, i.e.
GET/PUT/POST/DELETE
.
The following methods were added to the standard REST definition, for locking individual records and for handling database transactions (which speed up database process):
LOCK
to lock a member of the collection;UNLOCK
to unlock a member of the collection;BEGIN
to initiate a transaction;END
to commit a transaction;ABORT
to rollback a transaction.
The GET
method has an optional pagination feature, compatible
with the YUI DataSource Request Syntax for data pagination - see
TSQLRestServer.URI
method and http://developer.yahoo.com/yui/datatable/#data
. Of course, this breaks the "Every Resource is Identified by a Unique
Identifier" RESTful principle - but it is much more easy to work with, e.g. to
implement paging or custom filtering.
From the Delphi code point of view, a RESTful Client-Server architecture is implemented by inheriting some common methods and properties from a main class.
Then a full set of classes inherit from this TSQLRest
abstract
parent, e.g. TSQLRestClient TSQLRestClientURI
TSQLRestServer
.
This TSQLRest
class implements therefore a common ancestor for
both Client and Server classes.
BLOB fields
BLOB fields are defined as TSQLRawBlob
published properties in
the classes definition - which is an alias to the RawByteString
type (defined in SynCommons.pas
for Delphi up to 2007, since it
appeared only with Delphi 2009). But their content is not included in standard
RESTful methods of the framework, to spare network bandwidth.
The RESTful protocol allows BLOB to be retrieved (GET) or saved (PUT) via a specific URL, like:
ModelRoot/TableName/TableID/BlobFieldName
This is even better than the standard JSON encoding, which works well but convert BLOB to/from hexadecimal values, therefore need twice the normal size of it. By using such dedicated URL, data can be transfered as full binary.
Some dedicated methods of the generic TSQLRest
class handle
BLOB fields: RetrieveBlob
and UpdateBlob
.
JSON representation
The "04 - HTTP Client-Server" sample application available in the
framework source code tree can be used to show how the framework is AJAX-ready,
and can be proudly compared to any other REST server (like CouchDB)
also based on JSON
.
First deactivates the authentication by
changing the parameter from true
to false
in
Unit2.pas
:
DB := TSQLRestServerDB.Create(Model,ChangeFileExt(paramstr(0),'.db3'),
false);
and by commenting the following line in
Project04Client.dpr
:
Form1.Database := TSQLHttpClient.Create(Server,'8080',Form1.Model);
// TSQLHttpClient(Form1.Database).SetUser('User','synopse');
Application.Run;
Then you can use your browser to test the JSON content:
- Start the
Project04Server.exe
program: the background HTTP server, together with its SQLite3 database engine; - Start any
Project04Client.exe
instances, and add/find any entry, to populate the database a little; - Close the
Project04Client.exe
programs, if you want; - Open your browser, and type into the address bar:
http://localhost:8080/root
- OYou'll see an error message:
TSQLHttpServer Server Error 400
- Type into the address bar:
http://localhost:8080/root/SampleRecord
- You'll see the result of all
SampleRecord
IDs, encoded as a JSON list, e.g.[{"ID":1},{"ID":2},{"ID":3},{"ID":4}]
- Type into the address bar:
http://localhost:8080/root/SampleRecord/1
- You'll see the content of the
SampleRecord
of ID=1, encoded as JSON, e.g.{"ID":1,"Time":"2010-02-08T11:07:09","Name":"AB","Question":"To be or not to be"}
- Type into the address bar any other REST command, and the database will reply to your request...
You have got a full HTTP/SQLite3 RESTful JSON server in less than 400 KB. :)
Note that Internet Explorer or old versions of FireFox do
not recognize the application/json; charset=UTF-8
content type to
be viewed internally. This is a limitation of those softwares, so above
requests will download the content as .json
files, but won't
prevent AJAX requests to work as expected.
Stateless ORM
Our framework is implementing REST as a stateless protocol, just as the HTTP/1.1 protocol it could use as its communication layer.
A stateless server is a server that treats each request as an independent transaction that is unrelated to any previous request.
At first, you could find it a bit disappointing from a classic Client-Server approach. In a stateless world, you are never sure that your Client data is up-to-date. The only place where the data is safe is the server. In the web world, it's not confusing. But if you are coming from a rich Client background, this may concern you: you should have the habit of writing some synchronization code from the server to replicate all changes to all its clients. This is not necessary in a stateless architecture any more.
The main rule of this architecture is to ensure that the Server is the only reference, and that the Client is able to retrieve any pending update from the Server side. That is, always modify a record content on a server side, then refresh the client to retrieve the modified value. Do not modify the client side directly, but always pass through the Server. The UI components of the framework follow these principles. Client-side modification could be performed, but must be made in a separated autonomous table/database. This will avoid any synchronization problem in case of concurrent client modification.
A stateless design is also pretty convenient when working with complex
solutions.
Even Domain-Driven
Design tends to restrain state to its smallest extend possible, since state
introduces complexity.