Web API - Zpracování požadavků v mezipaměti (/serverstate)
Zpracování požadavků v mezipaměti umožňuje efektivní práci s business objekty (BO) prostřednictvím endpointu /serverstate
. Tento endpoint je navržen pro dočasné ukládání objektů do vyhrazené uživatelské mezipaměti, kde nad nimi lze provádět různé operace, jako je vytváření, načítání, aktualizace, ukládání nebo uvolňování z paměti. Tento přístup snižuje zátěž databáze a zajišťuje rychlejší odezvu aplikace při manipulaci s daty.
Endpoint /serverstate
podporuje pouze HTTP metodu POST
. Každý uživatel má vyhrazené vlákno, v jehož rámci je spravována mezipaměť. Požadavky v rámci stejného uživatelského přihlášení jsou serializovány, což znamená, že jsou zpracovávány postupně (tj. jak byly přijaty), aby se zabránilo kolizím. Vlákna uživatelských relací jsou alokována z dedikovaného poolu, odlišného od standardních požadavků, což umožňuje lepší správu výkonu a oddělení těchto operací. Vlákna tohoto poolu lze konfigurovat v souboru APIServer.yaml pomocí položek:
Tento systém podporuje i pokročilé funkce, jako je validace dat, vracení rozdílů pomocí JSON Patch a získávání metainformací o business objektech v mezipaměti. Díky tomu poskytuje vývojářům robustní nástroj pro práci s daty v reálném čase.

Požadavky na endpoint /serverstate
se vždy odesílají pomocí HTTP metody POST a mohou cílit buď na konkrétní business objekt v rámci relace, nebo obecně na relaci uživatele.
HTTP požadavek pro konkrétní business objekt:
POST {server}/{spojení}/{BO}/serverstate
HTTP požadavek pro obecné operace v rámci relace:
POST {server}/{spojení}/serverstate
Telo požiadavky:
{
"cacheid": "<string>",
"type": "<string>",
"breakiflocked": <boolean>,
"data": {
"object_id": "<string>",
"object_data": <object>,
"query": <query_object>,
"meta": {
"validation": {
"errors": <boolean>,
"warnings": <boolean>,
"objectdataerrors": <boolean>,
"queryerrors": <boolean>
},
"bodiff": {
"includeSource": <boolean>,
"ArraysByIDs": <boolean>
"AddJsonPath": <boolean>
"query": <query_object>
},
"boinfo":{
"types":["<string>"],
"includebefore": <boolean>,
"includeafter": <boolean>,
"includepatch": <boolean>
}
}
}
}
Význam jednotlivých parametrů:
Parameter | Význam | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Pomocí tohoto parametru si uživatel může rozdělit mezipaměť do více prostorů. S každým z nich se pracuje nezávisle (pokud se ale naplní sessionTimeoutMs, odstraní se všechny mezipaměti na uživateli). Lze použít i prázdnou hodnotu. Povinný parameter. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Povinný parameter. Aktuálně může obsahovat tyto hodnoty: ![]() Založí nový business object a vloží jej do mezipaměti. ![]() Načte existující business object a vloží jej do mezipaměti Pokud je aktivní pesimistické zamykání, pak se business objekt před vložením do mezipaměti zamkne a při uvolnění z mezipaměti odemkne. Odemknutí proběhne i pokud je mezipaměť vyprázdněna v důsledku timeoutu neaktivity klienta. Zámek lze převzít použitím breakiflocked s hodnotou true. Toto zamykání a odemykání probíhá stejně jako u běžného uživatele. Pokud se objekt nepodaří uzamknout, je vrácen status code 409. Pokud už objekt se stejným ID v mezipaměti je, operace load selže a vrátí status code 422. Pokud u operací očekávající použití elementu object_id (update, save, discard) business objekt v mezipaměti není, vrátí se status 404. V ostatních případech se vrací status 400 anebo případně další statusy, které se vracejí obecně (neexistující spojení, uživatel neautorizován apod). Typicky pokud během používání série operací update dojde k vrácení status 404, znamená to, že rozeditovaný objekt byl z mezipaměti odstraněn (pravděpodobně v důsledku timeout a vyčištění mezipaměti, resp. odhlášení uživatele). V takovém případě je nutné objekt do mezipaměti znovu založit (create, load, clone), a pokud si klient udržuje průběžně posílané změny, tak tyto změnu znovu poslat. Pro tento případ je možné s výhodou využít toho, že operace create, load, clone a update dokáží kromě jednoho požadavku zpracovat i pole požadavků, takže je možné je poslat najednou. Pokud při zpracování požadavku nedojde k chybě, je vždy vrácen status 200. ![]() Naklonuje existující business object a vloží jej do mezipaměti. ![]() Pošle změnu na business object držený v mezipaměti. ![]() Uloží business object držený v mezipaměti do databáze a uvolní jej z mezipaměti. ![]() Uvolní business object držený v mezipaměti. Typ discard umožňuje vyčistit buď specifickou mezipaměť, pokud je předán s neprázdnou hodnotou parametru cacheid, nebo všechny mezipaměti uživatele, pokud je parametr cashid zavolán bez hodnoty. Tento typ tedy slouží i kpřípadnému odemknutí pesimistického zámku. Při úspěšném provedení příkaz nevrací žádná data a vrací pouze stavový kód 204 (No Content). Požiadavka:
Telo požiadavky:
Výsledek zpracování dotazu: Status: 204 No Content ![]() Typ rolllookup Umožňuje zobrazit a filtrovat číselníky business objektů držených v mezipaměti, a to pouze za hodnoty, které jsou platné a použitelné v daném kontextu. Tento typ příkazu poskytuje efektivní způsob, jak získat omezené množství dat bez nutnosti manuálního nastavování filtrů nebo tokenů. Tělo požadavku, který se dotazuje na řádek faktury vydané a filtruje z něj ID, kód a název skladů z číselníku z tohoto řádku.
Více viz příklad č. 4. ![]() Možnost volat importní managery. Tento typ požadavku má dvě varianty chování, v závislosti na použití parametru ![]() Pokud je parametr output_document zadán:
Tato varianta umožňuje import dat do již existujícího objektu nebo do nově vytvořeného objektu s předem definovaným ID. Telo požiadavky:
![]() Pokud parametr output_document není zadán:
Tato varianta odpovídá chování před zavedením parametru output_document. Více viz příklad č. 2. ![]() Vrací pole informací cacheid, clsid, oid, objversion ze všech mezipamětí anebo jen za jednu mezipaměť, pokud je v těle zadáno cacheid. Požadavek na BO:
Telo požiadavky:
Výsledek zpracování dotazu: Status: 200 OK
Požadavek na obecný endpoint:
Telo požiadavky:
Výsledek zpracování dotazu: Status: 200 OK
Po úspěšném provedení create, load nebo clone je objekt vložen do mezipaměti. Po úspěšném provedení save nebo discard je objekt uvolněn z mezipaměti. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Nepovinný parametr. Východisková hodnota je false. Má smysl jen u operace typu load. Pokud je použito true, je aktivní pesimistické zamykání a business objekt je již zamknutý, provede se pokus o převzetí zámku. To se podaří, jen pokud má uživatel privilegium Opravovat záznamy, které již opravuje jiný uživatel. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Object ID (oid) business objektu. Má smysl jen u typu operací load, clone, update a discard (buď identifikuje BO v databázi nebo v mezipaměti). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Pomocí tohoto parametru se posílají změny na business object. Je možné jej použít u typu operací create, load, clone, update, save. Pokud se použije v souvislosti s operací, která vkládá BO do mezipaměti (create, clone, load) a během aplikace změn dojde k chybě, BO se z mezipaměti opět odstraní. Parametr není povinný. Může se jednat o jeden objekt reprezentující změny BO ve stejném formátu, jako se posílá na běžné endpointy business objektů anebo pole těchto objektů. Pokud se jedná o pole, pak jsou změny aplikovány postupně (pokud dojde k chybě, aplikování se přeruší). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Pomocí tohoto parametru lze specifikovat pole (fieldy), které se mají vrátit. Protože se jedná o dotaz proti BO v mezipaměti, je pro tento parametr podporována pouze hodnota select . Parametr je nepovinný a pokud se neuvede, vrací se všechny pole rozvinuté do první úrovně, stejně jako by se poslal dotaz na BO specifikovaný pomocí cesty /<BO>/<id>. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Tento objekt umožňuje zahrnout různé metainformace. A to: ![]() Objekt Pokud je Objekt obsahuje následující parametry:
Příklad vstupu:
![]() Objekt Objekt obsahuje následující parametry:
Výsledek zpracování skriptu:
IncludeSource je zadáno jako true, takže se v odpovědi vrátí i výsledky dotazů použité pro sestavení rozdílů (používá se spíše pro ladící účely). Vlastní query je specifikováno tak, aby vrátila rozdíly za všechny atributy objektu. ![]() Objekt
Tento požadavek vrátí informace o canupdate pouze pro uvedená pole: Person_ID, person_id.firstname, docqueue_id, docqueue_id.name, postaddress_id a postaddress_id.street. Požiadavka:
Telo požiadavky:
Výsledok spracovania požiadavky: Status: 200 OK
![]() Načtení objektu s kompletními metainformacemi:
Tento požadavek načte fakturu (BO) s ID 2LA0000101 a vrátí metainformace o všech položkách po provedení změn. Aktualizace objektu a vrácení pouze změn (patch):
Tento požadavek změní hodnotu položky vatdocument na false a vrátí pouze rozdíly (patch) mezi původním a aktuálním stavem. Výstup Stav po změnách (
Rozdíly (
Boinfo data jsou filtrována podle polí definovaných v sekci query. Prázdné kolekce (např. prázdné externalids) se do výsledku nezahrnují. ![]()
Položku @temporaryid server generuje automaticky (pokud není zadaná uživatelem) a při operaci clone ve stavu na serveru se vygeneruje automaticky na základě ID zdrojového řádku. Operace stavu na serveru týkající se nových řádků tak lze zopakovat se stejným výsledkem. |

Nejprve v mezipaměti vytvoříme novou fakturu vydanou.
Požiadavka:
POST http://localhost:81/demodata/issuedinvoices/serverstate
Telo požiadavky:
{
"cacheid": "xb1",
"type": "create",
"data": {
"object_data": {
"firm_id": "F011000000",
"docqueue_id": "5600000101",
"storedocqueue_id": "P600000101",
"rows": [
{
"@temporaryid": "ID1",
"rowtype": 0,
"text": "testovaci radek",
"division_id": "2100000101"
},
{
"@temporaryid": "ID2",
"rowtype": 3,
"store_id": "2100000101",
"storecard_id": "2100000101",
"unitquantity": 10,
"unitprice": 20.5,
"division_id": "2100000101"
}
]
}
}
}
Odpověď je zapouzdřena v elementu data. Pro další práci s touto fakturou vydanou je třeba z elementu data získat objid nové FV a z kolekce rows dohledat skutečná objid řádků pomocí @temporaryid (které se klientovi vrací na výstup beze změny). V dalších příkladech jsou tato objid uvedena s prefixem NEW_.
V dalším kroku aktualizujeme popis na faktuře, upravíme existující řádek, další řádek smažeme a doplníme nový řádek.
Hodnoty objid, které začínají na NEW_, je, jak bylo řečeno výše, třeba získat z dat po předchozím kroku a doplnit tyto konkrétní hodnoty.
Požiadavka:
POST http://localhost:81/demodata/issuedinvoices/serverstate
Telo požiadavky:
{
"cacheid": "xb1",
"type": "update",
"data": {
"object_id": "NEW_FV_OID",
"object_data": {
"description": "testovaci faktura",
"rows": [
{
"id": "NEW_ROW_OID_1",
"text": "zmena textu"
},
{
"@temporaryid": "ID4",
"rowtype": 0,
"text": "textovy radek c 2",
"division_id": "2100000101"
}
]
"rows@delete": {
"IncludeIDs": [NEW_ROW_OID_3]
}
}
}
}
V posledním kroku aktualizujeme položku unitquantity na řádku identifikovaném NEW_ROW_OID_2 a fakturu uložíme do databáze.
Požiadavka:
POST http://localhost:81/demodata/issuedinvoices/serverstate
Telo požiadavky:
{
"cacheid": "xb1",
"type": "save",
"data": {
"object_id": "NEW_FV_OID",
"object_data": {
"rows": [
{
"id": "NEW_ROW_OID_2",
"unitquantity": 12
}
]
}
"query": {
"select": [
"id"
]
}
}
}

V tomto příkladu provedeme import objednávky přijaté do dokladu Dodací list.
Mějme čerpatelnou objednávku přijatou s ID 15C0000101.
Požiadavka:
POST http://localhost:81/demodata/billsofdelivery/serverstate
Telo požiadavky:
{
"cacheid": "xb1",
"type": "import",
"data": {
"import_data": {
"input_document_clsid": "01CPMINJW3DL342X01C0CX3FCC",
"output_document_clsid": "050I5SAOS3DL3ACU03KIU0CLP4",
"input_documents": "15C0000101",
"params": {
"docqueue_id": "P600000101"
}
},
"object_data": {},
"query": {
"select": [
"ID"
]
}
}
}
Status: 200 OK
Výsledek zpracování dotazu:
{
"data": {
"ID": "49F0000101",
"@meta": {
"version": 1
}
}
}
Typ import má povinnou položku import_data, kde jsou zadána data importu ve standardním formátu jako v obyčejném importu. V položce object_data je stejně jako u jiných typů (create, load atd.) možné zadat seznam změn výsledného objektu. Nad objektem je možné provádět query a validaci. Pokud je import zavolán na endpointu serverstate nad BO, potom clsid výstupního dokumentu musí odpovídat clsid tohoto BO.

V sekci meta je možné získat ke každé výčtové položce seznam hodnot, které je na ní možné aktuálně nastavit pomocí objektu boinfo.
Telo požiadavky:
{
"cacheid": "cache66",
"breakiflocked": true,
"type": "load",
"data": {
"class": "issuedinvoices",
"object_id": "1LR0000101",
"object_data": {
"rows": [
{
"@temporaryid": "ID1",
"rowtype": 0
}
]
},
"query": {
"select": [
"id",
{
"name": "rows",
"value": {
"field": "Rows",
"query": {
"select": [
"ID",
"rowtype"
]
}
}
}
]
},
"meta": {
"boinfo": {
"types": [
"usableenums",
"canupdate"
],
"includeafter": true
}
}
}
}
Status: 200 OK
Výsledek zpracování dotazu:
{
"data": {
"id": "1LR0000101",
"rows": [
{
"ID": "1LU0000101",
"rowtype": 3
},
{
"ID": "3LU0000101",
"rowtype": 0,
"@temporaryid": "ID1"
}
],
"@meta": {
"version": 1,
"boinfo": {
"after": {
"rows": [
{
"id": "1LU0000101",
"rowtype": {
"canupdate": false,
"usableenums": []
}
},
{
"id": "3LU0000101",
"rowtype": {
"canupdate": true,
"usableenums": [
0,
1,
2,
3
]
}
}
]
}
}
}
}
}

V tomto příkladu vytvoříme v mezipaměti fakturu vydanou a následně vyfiltrujeme ID a kódy středisek z číselníku z druhého řádku této faktury pomocí typu rolllookup.
Skript v jazyce Python:
import base64
import json
import sys
import requests
from http_constants.headers import HttpHeaders
session = requests.Session()
headers = {}
headers[HttpHeaders.CONTENT_TYPE] = HttpHeaders.CONTENT_TYPE_VALUES.json
headers[HttpHeaders.AUTHORIZATION] = "Basic " + (
base64.urlsafe_b64encode(("Supervisor" + ":" + "").encode("utf-8"))
).decode("utf-8")
# uvolníme objekty z mezipaměti, aby bylo možné pouštět opakovaně
print("\ndiscard objects from cache:")
body = {"cacheid": "testRollLookUp", "type": "discard"}
response = session.post(
url="http://localhost:81/demodata/serverstate",
headers=headers,
json=body,
)
print(f"status code: {response.status_code}")
if response.status_code != 204:
sys.exit(0)
# založíme novou fakturu vydanou se 2 řádky
print("\ncreate fv:")
body = {
"cacheid": "testRollLookUp",
"type": "create",
"data": {
"object_data": {
"firm_id": "F011000000",
"docqueue_id": "5600000101",
"storedocqueue_id": "P600000101",
"rows": [
{
"@temporaryid": "ID1",
"rowtype": 0,
"text": "testovaci radek",
"division_id": "2100000101"
},
{
"@temporaryid": "ID2",
"rowtype": 3,
"store_id": "2100000101",
"storecard_id": "2100000101",
"unitquantity": 10,
"unitprice": 20.5,
"division_id": "2100000101"
}
]
}
}
}
response = session.post(
url="http://localhost:81/demodata/issuedinvoices/serverstate",
headers=headers,
json=body,
)
print(f"status code: {response.status_code}")
print("response body:")
print(json.dumps(response.json(), indent=2))
if response.status_code != 200:
sys.exit(0)
resp = json.loads(response.content.decode("utf-8"))
# Získáme id vytvořené faktury vydané
oid = resp["data"]["id"]
rows = resp["data"].get("rows", [])
# Získáme id druhého řádku
row2_id = next((row["id"] for row in rows if row["@temporaryid"] == "ID2"), None)
# Nyní použijeme rolllookup pro vyfiltrování id a kódů středisek z druhého řádku faktury
print("\nlook up division's IDs on the 2nd row:")
body = {
"cacheid": "testRollLookUp",
"type": "rolllookup",
"data": {
"class": "issuedinvoices",
"object_id": f"{oid}",
"field": f"rows/id:{row2_id}/store_id",
"query": {
"select": [
"ID",
"Code",
"Name"
]
}
}
}
response = session.post(
url="http://localhost:81/demodata/serverstate",
headers=headers,
json=body,
)
print(f"status code: {response.status_code}")
print("response body:")
print(json.dumps(response.json(), indent=2))
if response.status_code != 200:
sys.exit(0)
Výsledek zpracování dotazu:
Status: 200 OK
[
{
"ID": "2100000101",
"Code": "000",
"Name": "Centrála"
},
{
"ID": "1200000101",
"Code": "100",
"Name": "Prodej, služby"
},
{
"ID": "2200000101",
"Code": "200",
"Name": "Restaurace Na vršku"
},
{
"ID": "1300000101",
"Code": "300",
"Name": "Vývoj, výzkum"
},
{
"ID": "1400000101",
"Code": "400",
"Name": "Výroba"
},
{
"ID": "2400000101",
"Code": "401",
"Name": "Logistika a zásobování"
},
{
"ID": "3400000101",
"Code": "402",
"Name": "Výroba - dílna"
}
]