CodamAIDocs
Topicdone

Reading an object

How POST /read/{id} and GET /read/{id} work, what comes back for a missing or invisible object, and how singleton and abstract model differ.

Variants
POST /read/{id} with responseGET /read/{id} (= *)Singleton POST/GET /readabstract modelnot present → 404invisible → 404without read role → 403reference without read role → 403response missing → 400

What this is about

You know the id of an object and want to read it. Every model has two endpoints for this:

EndpointBodywhat comes back
POST {base}/read/{id}JSON with responseexactly the fields you list in response
GET {base}/read/{id}nonealways everything that ["*"] returns

{base} is the path of the model, for example /api/rest/hr/employee.

The two ways compared

POST: you choose the fields
Request
POST /api/rest/hr/employee/read/7f3…
{ "response": ["firstname", "lastname"] }
Response
{
  "data": {
    "id": "7f3…",
    "_createdOn": "2026-03-02 09:14:00",
    "_updatedOn": "2026-09-01 16:40:12",
    "firstname": "Daniel",
    "lastname": "Mertins",
    "company": null,
    "department": null
  },
  "meta": { "error": false }
}

id, _createdOn and _updatedOn always come along, even if they are not in response. Everything else you did not request is null in the response. More on this under System fields.

GET: always everything with *
Request
GET /api/rest/hr/employee/read/7f3…
Response
{
  "data": {
    "id": "7f3…",
    "firstname": "Daniel",
    "lastname": "Mertins",
    "company":    { "id": "a1…", "companyname": null },
    "department": { "id": "d4…", "name": null }
  },
  "meta": { "error": false }
}
POST or GET?
POST /read/{id}
for production
  • you choose the fields in response
  • you can expand references on purpose
  • you only need the roles of the models you actually request
GET /read/{id}
for trying things out
  • no body, CDMS always uses ["*"]
  • references come with their id only
  • needs the read role of every referenced model

The stations of a read request

A read request passes several checks. Data comes back only when all of them pass:

POST /api/rest/hr/employee/read/7f3…
  1. CIAS
    Filter chain
    Is the token valid?
    ↳ no 401
  2. CDMS
    Field selection
    Is there a response in the body?
    ↳ no 400 with messageKey response
  3. CDMS
    Model role
    Does the user have the read role of employee?
    ↳ no 403 missing-permission|employee-read
  4. CDMS
    Row filters
    Does the object exist, and may the user see it (tenant, own data, attribute filters)?
    ↳ no 404 not-found
  5. CDMS
    References
    Does the user have the read role of every model the response reaches into?
    ↳ no 403 missing-permission|<role>, the whole request fails
  6. 200 with the requested fields

Two things matter here:

  1. Invisible is the same as not present. An object that does not exist and an object you may not see both return 404. This way CDMS does not reveal that other people’s data exists. See Why invisible means 404.
  2. The response decides which roles you need. If you read only simple fields, the read role of the model is enough. As soon as the response reaches into a reference, you also need the read role of the referenced model.

All variants

Reading an object

When: The normal case. You know which fields you need.

  1. 1
    Client→CDMS
    sends POST /hr/employee/read/7f3… with { "response": ["firstname", "lastname"] }
  2. 2
    CDMS
    resolves the response into a list of fields
  3. 3
    CDMS
    checks the read role of employee
  4. 4
    CDMS→Database
    looks for the row with this id, restricted by the row filters, and reads only the requested columns
  5. 5
    Hook
    the project's read hooks see the object before it becomes the response
  6. 6
    CDMS→Client
    returns the object in data

Result: 200 with firstname, lastname and the system fields.

When: You want to look at an object quickly, for example with curl or in the browser.

The flow is the same as with POST. CDMS just sets response to ["*"] itself. You get all simple fields and every reference with its id. For this you need the read role of every referenced model.

Result: 200 with everything * returns, or 403 if a reference role is missing.

When: The model has exactly one object, e.g. settings. Path without id: POST /read or GET /read.

  1. 1
    Client→CDMS
    sends POST /crm/einstellungen/read with { "response": ["+"] }
  2. 2
    CDMS→Database
    finds the one object itself, with the row filters
  3. 3
    CDMS→Client
    none there → 404 no-object-found
  4. 4
    CDMS→Client
    present → reads it like a normal object

Result: 200 with the one object. See Singletons.

When: You read through the hub API of an abstract model, e.g. /crm/kunde/read/{id}.

  1. 1
    Client→CDMS
    sends only the id, no @type
  2. 2
    CDMS→Database
    looks up the stored type for the id, e.g. crm.privatkunde
  3. 3
    CDMS
    passes the request on to the API of the subtype, with its roles and filters
  4. 4
    CDMS→Client
    returns the object with @type

Result: 200 with the fields of the subtype and "@type": "crm.privatkunde". See Abstract models.

When: The user lacks the role employee-read.

  1. 1
    Client→CDMS
    sends a valid read request
  2. 2
    CDMS
    checks the read role of employee
  3. 3
    CDMS→Client
    role missing → 403 missing-permission|employee-read

Result: 403. The database is not even asked.

When: The id does not exist, or the object belongs to another user or is excluded by an attribute filter.

  1. 1
    CDMS→Database
    looks for the row with the id and all row filters
  2. 2
    CDMS→Client
    no row found → 404 not-found

Result: 404. The client cannot tell whether the object does not exist or whether it may not see it.

Decision table

Response to POST /hr/employee/read/{id}
response in bodyrole employee-readobject visibleroles of the requested referencesResponse
no–––400 response
yesno––403 missing-permission|employee-read
yesyesno–404 not-found
yesyesyesone is missing403 missing-permission|<role>
yesyesyesall present or none requested200

The table describes the default, strict mode. When it is switched off, status and key change: without employee-read you get 404, and a single reference without the role is silently null. See Strict mode.

Pitfalls

Where to go next

Sources in the code and the knowledge base
  • CDMS/cdms-generator – ApiProcessor, ApiSingletonProcessor (read-by-post, read-by-get)
  • CDMS/cdms-rest-api – AbstractRestApi.readObject, AbstractRestSingletonApi.readObject, AbstractHubApi.read, Expander
  • CDMS/cdms-system-layer – AbstractSystemLayer.readObject, AbstractLayer.recursiveRead
  • CDMS/cdms-authorization – AbstractAuthorizationLayer.classAccess
  • documentation/05-api-guide/04-lesen.md
Search