Skip to main content

SpEL Clients

The tSM service clients are the SpEL façade wrapped around every public REST endpoint the platform exposes. Each client is referenced in SpEL exactly the same way you already call other services – by its bean name, e.g. @crm.customer, @register.value, @inventory.product, …


1 Essentials in a Nutshell

1.1 Five flavours of clients

Client familyTypical IDSignature highlightsWhen to use
CRUDUUIDget / create / update / patch / deleteEveryday single-record work
Filteringfind(criteria, options)Searches with paging & sorting
Code-basedBusiness codeget(idOrCode), update(idOrCode), ...
findAllByCode, findAllByCodeIn
Entities with CODE (registers, lookup tables, catalogues)
Key-basedBusiness keyget(idOrKey), update(idOrKey), ...
findByKey, findAllByKeys
Entities with KEY (business ID - customers, tickets, orders, ...)
BulkUUID / code / key listbulkGet / bulkCreate / bulkUpdate / bulkPatch / bulkDeleteMass operations on hundreds of rows

All families share the same calling conventions:

@area.entity.method(arg1, arg2, …)
  • First argument – mandatory (ID, map of criteria, list of IDs …).
  • Second argumentquery options (see § 3). Omit it when you are fine with the sensible defaults.

1.2 30-second cheat-sheet

// ❶ CRUD — single record
#customer   = @crm.customer.get('7357b234-…-f1b2')
@crm.customer.patch('7357b234-…', {description:'VIP'})

// ❷ Filtering — list, paging & sorting
#b2b        = @crm.customers.find(
                {type:'B2B', name__contains:'Acme'},
                {sort:'name,ASC', page:0, size:20})

// ❸ Code-based look-up
@register.value.findAllByCode('COUNTRY_CZ')

// ❹ Child-of-code look-up
@register.value.get('CZ', 'Country')

// ❺ Key-based look-up
#accounts  = @crm.account.findByKey('CON-2024-0001')

// ❻ Bulk
@crm.customers.bulkDelete(['id1','id2','id3'])

1.3 Query-options — override when you need to

FlagWhere supportedExampleNotes
cacheAll get / find methods{cache:false}Register types entites cache by default, others don’t.
expandEndpoints that support nested data{expand:['PRIMARY_ADDRESS','CONTACTS']}Pass enum names shown by autocomplete.
sortFiltering client"name,ASC,code,DESC"Comma-separated field,dir pairs.
page, sizeFiltering client{page:0, size:50}Both values are zero-based.
asyncAll mutations{async:true}Fire-and-forget, returns immediately with null.
immediateRefreshSpecial CRUD variants{immediateRefresh:true}Forces ES re-index before returning.

Tip Autocomplete (Ctrl + Space) suggests all option keys and permitted expand values.

Rule of thumb – supply only the flags you actually need; everything else is inferred from per-client defaults.


2 Client Families & Method Reference

2.1 Identifiers, Keys & Codes – the four access patterns

VariantFirst argument(s)Typical client familiesUse-case
ID'7357b234-…-f1b2' (UUID)CRUD, BulkInternal primary key
ID or Key'CON-2025-0005' or UUIDKey-based, BulkBusiness ID
ID or Code'WOOD' or UUIDCode-based, BulkCatalogue / register
Child + Parent'CZK', 'CURRENCY'Child-of-code CRUDLook-ups nested by parent code

Mnemonicid, key, code and code+parent cover 99 % of data-access scenarios on the platform.


2.2 Filtering Client – powerful searches

#results = @crm.customers.find(
    {type:'B2B', name__like:'*Acme*'},          // criteria
    {sort:'name,ASC', page:0, size:25}          // options
)
  • Criteria map understands comparison suffixes (__eq, __lt, __like, __in, …).
  • Paging & sorting flags mirror standard Spring conventions.
  • Searches are not cached unless you add {cache:true}.

2.3 Code-based Client – look-ups by business code

MethodPurposeExample
get(idOrCode, opt?)Load by UUID or code@catalog.item.get('WOOD')
findAllByCode(code, opt?)0 – ∞ matches@catalog.item.findAllByCode('WOOD')
findAllByCodeIn([codes], opt?)Batch look-up@catalog.item.findAllByCodeIn(['WOOD','STEEL'])
update / patch / delete(idOrCode, …)Mutations – UUID or code

2.4 Child-of-code Client – code + parent code

MethodPurposeExample
get(code, parentCode, opt?)Load one child@register.value.get('CZK','CURRENCY')
patch(code, parentCode, changes)Partial update@register.value.patch('CZK','CURRENCY',{rate:25.7})
delete(code, parentCode [, opt])Remove@register.value.delete('CZK','CURRENCY')

2.5 Key-based Client – look-ups by business key

MethodPurposeExample
get(idOrKey, opt?)UUID or key@billing.contract.get('CON-2025-0005')
findByKey(key, opt?)0 – ∞ matches for one key@billing.contract.findByKey('CON-2025-0005')
findAllByKeys([keys], opt?)Multi-key look-up@billing.contract.findAllByKeys(#keys)
Mutations (update / patch / delete)UUID or key

2.6 Bulk Clients – do everything in one request

OperationPurposeExample
bulkGet(idsOrKeysOrCodes, opt?)Batch read@crm.customers.bulkGet(#ids)
bulkCreate(list, opt?)Batch insert@catalog.items.bulkCreate(#dtos)
bulkUpdate(list, opt?)Batch replace@catalog.items.bulkUpdate(#dtos)
bulkPatch([[id,key,code], patch], … , opt?)Batch partial update@catalog.items.bulkPatch(#changes)
bulkDelete(idsOrKeysOrCodes, opt?)Batch remove@crm.customers.bulkDelete(#ids)

Bulk updates honour async and immediateRefresh exactly like single-record calls.

3 Transactions & Execution Context

TL;DR Everything you do in a SpEL script is executed inside one specific microservice. Local service calls are transactional and roll back on error. Remote HTTP calls are not – unless you flag them async so they are queued only after the local commit succeeds.


3.1 Which microservice am I running in?

  • Every SpEL script is hosted by exactly one microservice – the one that started the script (order-process engine, CRM event handler, document workflow, …).
  • In the SpEL Console you must pick that microservice in the Service selector before you hit Ctrl + Enter.
  • All context variables (#order, #ticket, #currentUser(), …) and default cache settings come from this host microservice.
Where the script runsTypical triggersBuilt-in context you get
Ordering MicroserviceBPMN task, Order event#order, #task, #productCodes()
CRM MicroserviceCustomer event, API hook#customer, #account, #contact
Billing MicroserviceInvoice process#contract, #invoice
(etc.)

3.2 Local vs. remote calls

Call targetHow the client is invokedPart of the hosting TX?Roll-back behaviour
Same microserviceDirect in-process method✔︎Data is rolled back if the outer script fails.
Different microserviceHTTP request (REST)Remote change is permanent; the host cannot undo it.
// LOCAL – transactional
@crm.customer.patch(#id, {status:'Processing'})   // ← runs in same CRM MS

// REMOTE – *not* transactional
@billing.billingDocument.patch(#id, {state:'Cancelled'}) // ← HTTP to Billing MS

3.3 Making remote work safe – the async flag

When you need a remote update that must respect your current transaction use asynchronous mode:

@billing.billingDocument.patch(
    #id,
    {state:'Cancelled'},
    {async:true}           // ← nothing is sent until *after* commit
)
  • The call is not executed immediately. Instead, a message is written to Kafka after the local transaction commits successfully.
  • If the transaction rolls back, no message is emitted – the remote system never sees the request.
  • The original SpEL call returns null right away (fire-and-forget).

Rule of thumbLocal changes? → plain call. Remote changes that must follow your commit?async:true. Simple remote fire-and-forget where roll-back is irrelevant? → plain call.


3.4 Quick checklist

  1. Know your host – pick the correct microservice in the console.
  2. Local client = transactional – full ACID safety.
  3. Remote client ≠ transactional – use async:true if you need atomicity.
  4. Kafka queue guarantees delivery after commit, but processing still happens eventually, not synchronously.

With these rules in mind you can chain service calls confidently without unintended side-effects. Happy scripting!


4 Development & Debugging

Autocomplete & Console Tips

  • @ + Ctrl Space List all service clients.
  • . + Ctrl Space Methods & their docs.
  • Wrap query-options in { } to get live suggestions for every flag.
  • Double Ctrl Space anywhere shows a full description of the highlighted suggestion.

Where to look up the full method catalogue

The client families described in chapter 1.1 map 1-to-1 to the endpoints of the Public REST API. Whenever you need the exact signature, parameter list or response schema, open the Swagger documentation shipped with every microservice:

Location in UIWhat it listsWhen to use
spel-xxx-client (e.g. spel-crm-client)Only the client methods & their query-option objects.Fast look-up while writing SpEL – concise and free of noise.
spel-crm-methods (or analogous name)Business-level helper functions implemented inside the microservice.Discover domain-specific shortcuts (approveOrder, calculateDiscount, …).
spel-all-methodsEverything the microservice exposes – business methods, low-level core helpers and every client method.Reference & debugging; the list is huge.
v2Standard Public API (OpenAPI v3).When you integrate over HTTP from outside tSM.
v1Legacy Public API.Needed only for backward compatibility.

Tip – start with spel-xxx-client for day-to-day SpEL work. It shows exactly the calls you can embed in a script, organised and documented just for that purpose.

Public API


Happy automating – and may your transactions always commit exactly the way you expect!