Menu

Accessing Backend

Csaba Skrabák

Full Declarative Mode

No backing script necessary.

<t:container {product}>
    <table>
        <thead>
             <tr>
                 <td>Name</td>
                 <td>Price</td>
             </tr>
        </thead>
        <tbody>
            <tr {rows}>
                <td>{name}</td>
                <td>{price}</td>
            </tr>
        </tbody>
    </table>
    <p>Displaying {offset} to {offset+rows} of {count}.</p>
</t:container>
  1. Engine: typeof product == "undefined" ==> http://localhost/ << GET /product
  2. Service: SELECT count(*) FROM product + SELECT * FROM product ORDER BY 1 OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY >> JSON {"count":...,"offset":...,"limit":...,"rows":[...]}>> response
  3. Engine: product = JSON.parse(responseBody)

Train station

Idea of putting instructions in a queue that is emptied on a time schedule.

CrudPage

Idea: the app developer can instantiate a framework-defined class to fetch a page of JavaScript objects corresponding persisted data (page has finite length, specified by the app developer, and is an array indexed by the result's in-page ordinal number). Changes to the JavaScript proxy objects are tracked (can be committed/fetched by function calls or on a time schedule). Changes to the page number are tracked as well. The framework would be able to convert the changes to the JavaScript objects into CRUD operations on a RESTful API.

var products = new CrudPage(50, "http://localhost:8080/api/products")

The CrudPage class has Observable properties corresponding each field of the JSON object that is expected in response to a GET request on the specified URL.

Setters of offset and limit will send a new GET request.
Proxy objects of the fetched rows are in the rows field.

CrudSet

Same as CrudPage but instead of limiting the result set by count, we fetch a predefined set of IDs. The proxy objects will be indexed by ID in a JavaScript object.

var userPreferences = CrudSet.of(["userName", "dob"], `http://localhost:8080/api/user/${uid}`)

Optimistic Concurrent CRUD APIs

Problem: when updating, the transaction should succeed only if there was no concurrent modification in the database between fetching and updating.
Solution:

  • CREATE and READ responses include a MAC digest of the created/read document.
  • With UPDATE and DELETE operations, the client will send the MAC digest of the original document that the operation is meant to be done with.
  • On database side, when handling the UPDATE or DELETE request, in the same transaction, first check if currently stored version of the document in question matches the MAC digest received together with the request. If not, fail the transaction. If yes, do update or delete, finishing the transaction.

Reponse to a READ request (multiple results)

{
    "versionAlgorithm": "SHA-3-256",
    "rows": [
        {
            "version": "d57f44aeb26cbe12577d46bde1f11dd189c30a59c3e07d8461f5aa2cdada90c7",
            "id": 1000,
            "content": {
                "field1": 1,...
            }
        },...
    ]
}

Two clients request the same record. The record was not modified in between the two read requests. Both clients will get the same version code.
Next, one of these clients requests an UPDATE to this same record.
UPDATE request:

{
    "versionAlgorithm": "SHA-3-256",
    "version": "d57f44aeb26cbe12577d46bde1f11dd189c30a59c3e07d8461f5aa2cdada90c7",
    "id": 1000,
    "content": {
        "field1": 20,...
    }
}

Success. The version changes in the database.
The other client wants to UPDATE after this:

{
    "versionAlgorithm": "SHA-3-256",
    "version": "d57f44aeb26cbe12577d46bde1f11dd189c30a59c3e07d8461f5aa2cdada90c7",
    "id": 1000,
    "content": {
        "field1": 101,...
    }
}

Since this client did not notice the modification that happened concurrently, it sends the old version of the record.
Database checks version and notices mismatch. Sends error response. Refuses to do the modification.

Happy ending: the clients could not overwrite each other's changes.


Note: the structure described above is only for the request/response bodies, which is not reflected in the JavaScript objects (proxies, CrudPage properties, CrudSet properties, names appearing in a bracy template therefore stay the same as without concurrency awareness; e.g. things like {content}, {versionAlgorithm} are undefined.)

SQL interface

A lower level alternative for accessing a database. I'm not really a fan, I think that the construction of database queries belong to the backend's side but hey.

Element Annotations

We need [Element Annotations] to make the pager/CRUD classes work in full declarative mode.


Related

Wiki: Home

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.