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í}/serverstate
HTTP požadavek pro obecné operace v rámci relace:
POST {server}/{spojení}/serverstate
Tělo požadavku:
{
"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>,
"AddJsonPath": <boolean>
"query": <query_object>
},
"boinfo":{
"types":["<string>"],
"includebefore": <boolean>,
"includeafter": <boolean>,
"includepatch": <boolean>
}
}
}
}
Význam jednotlivých parametrů:
Parametr | 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ý parametr. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Povinný parametr. 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žadavek:
Tělo požadavku:
Výsledek zpracování dotazu: Status: 204 No Content ![]() Typ fieldlookup 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ů. Umožní také získat nastavitelné hodnoty pro položku typu odkaz na doklad. 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. Tělo požadavku:
![]() 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:
Tělo požadavku:
Výsledek zpracování dotazu: Status: 200 OK
Požadavek na obecný endpoint:
Tělo požadavku:
Výsledek zpracování dotazu: Status: 200 OK
Typy operací create, update, clone a import podléhají patřičným právům k funkcím (opravit a přidat) v nastavení práv. 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ýchozí 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>. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Pokud je tento příznak zadaný s hodnotou false, nebudou se do výsledku vypisovat hodnoty datových polí, výsledek bude obsahovat pouze sekci “@meta”. Výchozí hodnota: true Příklad použití příznaku returndata
Tělo požadavku:
Výsledek zpracování dotazu: Status: 200 OK
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
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:
Při porovnání dvou JSON uzlů typu objekt se vygeneruje patch operace REPLACE, pokud je jeden z uzlů prázdný nebo obsahuje hodnotu `null`.
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žadavek:
Tělo požadavku:
Výsledek zpracování požadavku: 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 (
Další příklad ukazuje využití informací insertable o kolekci a deletable, editable ohledně řádku kolekce:
Tělo požadavku:
Odpověď:
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. |

Endpoint /sessions/terminatecurrent
slouží k ukončení aktuální uživatelské session. Volání tohoto endpointu zároveň uvolní kompletní serverstate cache patřící aktuálnímu uživateli. Tento endpoint je užitečný pro explicitní odhlášení uživatele.
POST /{server}/sessions/terminatecurrent
Pro tento endpoint se nekontrolují žádná práva, protože uživatel může ukončit pouze svoji vlastní session.

Nejprve v mezipaměti vytvoříme novou fakturu vydanou.
Požadavek:
POST http://localhost:81/demodata/serverstate
Tělo požadavku:
{
"cacheid": "xb1",
"type": "create",
"data": {
"object_data": {
"class": "issuedinvoices",
"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žadavek:
POST http://localhost:81/demodata/serverstate
Tělo požadavku:
{
"cacheid": "xb1",
"type": "update",
"data": {
"class": "issuedinvoices",
"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žadavek:
POST http://localhost:81/demodata/serverstate
Tělo požadavku:
{
"cacheid": "xb1",
"type": "save",
"data": {
"class": "issuedinvoices",
"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žadavek:
POST http://localhost:81/demodata/serverstate
Tělo požadavku:
{
"cacheid": "xb1",
"type": "import",
"data": {
"class": "billsofdelivery",
"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.
Tělo požadavku:
{
"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 fieldlookup.
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": "testFieldLookUp", "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": "testFieldLookUp",
"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 fieldlookup 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": "testfieldLookUp",
"type": "fieldlookup",
"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"
}
]
V dalším příkladu si ukážeme volání funkce fieldlookup, která vrátí objednávky přijaté z dodacích listů, které je možné nastavit do parametru selectedheader.
Nejprve vytvoříme importního manažeru DL->FV
{
"cacheid": "cache",
"type": "create",
"data": {
"class": "ZUMBGNJTXF44H4YIMBETLJJRQ0",
"object_data": {
"inputdocuments": [
"59W1000101", "29Y1000101"
]
},
"query": {
"select": [
"id",
"selectedheader"
]
},
"meta": {
"validation": {
"errors": true,
"warnings": true
},
"objectdiff": {
"includesource": true,
"addjsonpath": true
},
"objectinfo": {
"types": [
"canupdate",
"usableenums"
],
"includebefore": true,
"includeafter": true,
"includepatch": true
}
}
}
}
Volání funkce fieldlookup vrátí objednávky přijaté z dodacích listů které je možné nastavit do parametru selectedheader.
{
"cacheid": "cache",
"type": "fieldlookup",
"data": {
"object_id": "CWZHRXCCDOY4VGKSAZCCMNCQ20",
"field": "selectedheader",
"class": "ZUMBGNJTXF44H4YIMBETLJJRQ0",
"query": {
"select": [
"id",
"displayname"
]
}
}
}

Příklad ukazuje vytvoření nové řady pro fakturu vydanou pomocí přidané sekce forreference, proto předáme jako vazební pole issuedinvoice, docqueue_id konkrétní faktury.
Do mezipaměti nahrajeme fakturu vydanou a poté si necháme vytvořit novou řadu, tak, aby přesně vyhovovala požadavkům na použití ve faktuře vydané. V sekci select jsme si zvolil, že z nové řady chceme jen tyto položky id, documenttype, code
Nejprve nahrajeme do keše serverstate fakturu vydanou
{
"cacheid": "",
"type": "load",
"data": {
"class": "issuedinvoices",
"object_id": "3L50000101",
"query": {
"select": [
"id"
]
}
}
}
Výsledek zpracování dotazu:
{
"data": {
"id": "3L50000101",
"@meta": {
"version": 1
}
}
}
Poté necháme vytvořit novou řadu, tak, aby přesně vyhovovala požadavkům na použití ve faktuře vydané. V sekci select jsme zvolili, že z nové řady chceme jen položky id, documenttype, code
{
"cacheid": "",
"type": "create",
"data": {
"class": "docqueues",
"object_data": {},
"forreference": {
"class": "issuedinvoices",
"object_id": "3L50000101",
"field": "docqueue_id"
},
"query": {
"select": [
"id",
"documenttype",
"code"
]
}
}
}
Výsledek zpracování dotazu:
{
"data": {
"id": "2O70000101",
"documenttype": "03",
"code": "FV",
"@meta": {
"version": 1
}
}
}