CodamAIDocs
Topicdone

Wildcards + and *

How you request many fields at once with + and *, what the partial wildcards name+, +name, name* and *name match, and why * needs more permissions than you might think.

Variants
+ alone* alonePrefix: name+ / name*Suffix: +name / *nameCombining several entriesexcludeWildcard without matchesMarker in the middle of a wordGET /read = ** without read permission on a reference

What this is about

Every time you read data, you tell CDMS in the response list which fields you want back. You can name every field one by one. For models with many fields this is tedious, so there are two shortcuts, the wildcards:

CharacterHow to remember itreturns
+“plus the simple fields”all simple fields: text, number, date, yes/no
*“star is more”all simple fields and all references (lists too), but references only with their id

The example model

All pictures on this page use the same model employee:

FieldKindExample value
idsimple"7f3…"
firstnamesimple"Daniel"
lastnamesimple"Mertins"
companyreference to company{ "id": "a1…" }
departmentreference to department{ "id": "d4…" }

The two basic forms

+ and * on the model employee
simple fieldreferencereturned
RequestResult
["+"]
idfirstnamelastnamecompanydepartment
Only the simple fields. The references are missing.
["*"]
idfirstnamelastnamecompany (id only)department (id only)
Simple fields and both references, the references only with their id.
The same request with * as request and response
Request
POST /api/rest/hr/employee/read/7f3…
{ "response": ["*"] }
Response
{
  "data": {
    "id": "7f3…",
    "firstname": "Daniel",
    "lastname": "Mertins",
    "company":    { "id": "a1…", "companyname": null },
    "department": { "id": "d4…", "name": null }
  },
  "meta": { "error": false }
}

If you need more than the id of a reference, you expand it explicitly. This is explained under Expand references.

The partial wildcards

You can combine both characters with the start or the end of a word. The character goes either at the very front or at the very end:

Formreads asmatches
name+“simple fields that start with name”prefix
+name“simple fields that end with name”suffix
name*like name+, plus references that start with nameprefix
*namelike +name, plus references that end with namesuffix
All partial wildcards on the model employee
simple fieldreferencereturned
RequestResult
["+name"]
idfirstnamelastnamecompanydepartment
Both end with name.
["first+"]
idfirstnamelastnamecompanydepartment
Only firstname starts with first.
["*ment"]
idfirstnamelastnamecompanydepartment (id only)
department is a reference and ends with ment. With * it is included, but only with id.
["depart*"]
idfirstnamelastnamecompanydepartment (id only)
The same result using the start of the word.
["+pany"]
idfirstnamelastnamecompanydepartment
company does match pany, but it is a reference, and + never includes references. Result: no field, but still 200.
["first+name"]
idfirstnamelastnamecompanydepartment
The character is in the middle of the word. That is not a wildcard and matches nothing, not even firstname. No error, just empty.

How CDMS resolves a wildcard

A component in the REST layer, the Expander, does the resolving. For each entry of the response list it works like this:

flowchart TB
    E["Entry from response"] --> Q1{"Is it an object<br/>{ field, response }?"}
    Q1 -->|yes| R["Expand the reference explicitly<br/>(separate page)"]
    Q1 -->|no| Q2{"Does the text contain<br/>+ or * at the start<br/>or at the end?"}
    Q2 -->|no| F["take exactly this field"]
    Q2 -->|"yes, +"| P["all simple fields<br/>whose name matches"]
    Q2 -->|"yes, *"| S["all simple fields whose name matches<br/>+ all references whose name matches<br/>(only with id)"]
    P --> X["subtract exclude"]
    S --> X
    F --> Z["Result: list of fields<br/>→ exactly these columns are read from the DB"]
    X --> Z

Four rules you should remember:

  1. Start or end of a word, nothing else. There are no regular expressions, no character in the middle of a word, and never two characters in one entry.
  2. Upper and lower case matter. +Name does not match firstname.
  3. Several entries are added together. ["+name", "*ment"] returns firstname, lastname and department.
  4. No match is not an error. A wildcard that matches nothing simply returns no fields, and the response is still 200.

Removing fields again: exclude

With exclude you remove single fields from the result of a wildcard:

Request
{ "response": ["*"], "exclude": ["department"] }
Response
{ "data": { "id": "7f3…", "firstname": "Daniel",
            "lastname": "Mertins", "company": { "id": "a1…" },
            "department": null } }
When does exclude work?
works
  • on fields that were added by a wildcard
  • ["*"] + exclude: ["department"] → department is missing
does not work
  • on fields you requested by name
  • ["department", "+"] + exclude: ["department"] → department is still there

All variants at a glance

What happens with which request

When: You need all simple fields and no references.

  1. 1
    Client→CDMS
    sends { "response": ["+"] }
  2. 2
    CDMS
    includes all simple fields of the model
  3. 3
    CDMS→Database
    reads exactly these columns, without a join

Result: All simple fields. References appear as null in the response.

When: You want a quick overview of everything, including the references.

  1. 1
    Client→CDMS
    sends { "response": ["*"] }
  2. 2
    CDMS
    includes all simple fields and all references
  3. 3
    CDMS
    checks the read role of the referenced model for every reference
  4. 4
    CDMS→Database
    reads the columns and fetches every reference with a LEFT JOIN, but only its id

Result: All simple fields, plus every reference as { "id": … }.

When: You want a group of similarly named fields, for example all …Date fields.

Like + or *, except that the fields are filtered by name first. The character goes at the front (suffix search) or at the end (prefix search).

Result: Only the fields whose name matches. + never with references, * with matching references.

When: You take a quick look at an object, for example in the browser or with curl.

GET has no body, so it has no response either. CDMS then always uses ["*"].

Result: Same as *. Good for trying things out, bad for production, because you need more data and more permissions than necessary.

When: The user may read employee, but not company.

  1. 1
    Client→CDMS
    sends { "response": ["*"] }
  2. 2
    CDMS
    * includes company, so the read role of company must be present
  3. 3
    CDMS
    The role is missing. The whole request fails, the reference is not simply left out.

Result: 403 with missing-permission|company-read

The two traps

Trap 1: null does not mean “empty”

The response always contains the whole object. Fields you did not request appear as null, they are not missing. So with firstname: null you do not know whether the field is empty or whether you just did not request it.

Trap 2: * needs the permissions of all references

Request on employee – who gets what?
responseRole employee-readRole company-readRole for departmentResponse
["+"]yes––200 – only simple fields, no reference is read
["*"]yesnoyes403 missing-permission|company-read – the whole request fails
["*"]yesyesyes200 – everything is there
["id","firstname"]yes––200 – requested by name, no reference involved

A ["*"] that works for you can fail for a colleague who has fewer roles.

Why all this? The effect on the database

The response is not a filter that removes fields from the response afterwards. It already decides what is read from the database: CDMS builds a query that reads exactly the requested columns and attaches references with a LEFT JOIN. So a + on a model with 40 fields reads 40 columns, ["id", "name"] only two.

flowchart LR
    A["response: ['id','firstname','*ment']"] --> B["Expander<br/>→ id, firstname, department.id"]
    B --> C["SQL: SELECT e.id, e.firstname, d.id<br/>FROM employee e<br/>LEFT JOIN department d …"]
    C --> D["Response with exactly these values"]
Sources in the code and the knowledge base
  • documentation/05-api-guide/04-lesen.md
  • documentation/20-api/03-response-requests.md
  • CDMS/cdms-rest-api – Expander
Search