API access
[ApiAccess] limits API access. RBAC must also allow the operation, even for administrators.
Server code still follows normal business rules.
Entity operations
Apply entity settings to classes or interfaces:
[ApiEntity]
[ApiAccess(EntityAccess.Read | EntityAccess.Update)]
public partial class Transaction
{
[Property<DataTypes.Currency>("Amount")]
[ApiAccess(PropertyAccess.ReadOnly)]
public partial decimal Amount { get; set; }
[Property<DataTypes.Boolean>("Clear")]
public partial bool Clear { get; set; }
}
Clients can read Transaction and update Clear. They cannot create or delete Transaction, or change Amount.
Mark its other protected fields ReadOnly too.
| Entity value | Allowed operation |
|---|---|
None |
None |
Read |
Read records |
Create |
Create records |
Update |
Update existing records |
Delete |
Delete records |
Full |
All four operations |
Combine flags with |. Full = Read | Create | Update | Delete is the default.
Writes without Read return success and prompts, without entity data.
Property access
| Property value | Client behavior |
|---|---|
ReadWrite |
Read and supply values during creation or update |
ReadOnly |
Read, without supplying values |
Hide |
No reads or writes |
ReadWrite is the default. Properties cannot allow operations blocked by their entity or a missing setter.
| Entity setting | Property setting | Effective property operations |
|---|---|---|
| Unconfigured | Unconfigured | Read, create, update |
| Unconfigured | ReadOnly |
Read |
Read | Update |
Unconfigured | Read, update |
Read | Update |
ReadOnly |
Read |
Read |
ReadWrite |
Read |
Full |
Hide |
None |
References and their generated GUID fields share restrictions: hiding Customer also hides CustomerGuid.
Inheritance
Every declaration on an entity, base class, or inherited interface must allow the operation, including across assemblies.
Properties keep the strongest inherited restriction. Declaring Full cannot undo an inherited Read restriction.
Base endpoints honor the actual record type. Base queries exclude unreadable derived records before counting or searching. They block fields restricted by readable subtypes and navigations that can target unreadable subtypes. Wildcard responses may omit these fields too. Use a concrete entity endpoint for its own allowed fields.
Requests, responses, and permissions
Blocked operations or fields return HTTP 403 before setters or deserialization hooks run. One blocked field rejects the whole request. Nested writes and batch operations use the same checks. Assigning a reference writes that property; it does not update the target.
Hidden fields never appear in responses, including nested data and prompt envelopes. Queries, filters, sorting, computations, aggregates, and search cannot expose their values. Metadata still lists their names and access settings so clients can hide controls.
Collection payloads replace membership. Existing children update only supplied fields; omitted values stay unchanged. New children need Create, existing children need Update, and removed children need Delete. Each supplied field also needs write access.
Updates need RBAC list access and write permission for each supplied field, without create permission:
grant.Entity<Transaction>()
.View()
.Read(t => t.Amount)
.Write(t => t.Clear);
Create, delete, and [Method] permissions keep their existing rules. Blocking CRUD does not block methods.
Clients combine ApiAccess metadata, RBAC, setters, and business rules to hide or disable controls.
IsQueryReadable controls query paths. It does not change the property's declared write access.
Graph editors need read access and a readable GUID. Field changes after creation use PATCH and need Update.
Migration from ReadOnly attribute settings
Replace the removed ReadOnly attribute arguments:
| Former declaration | Replacement |
|---|---|
[ApiEntity(ReadOnly = true)] |
[ApiEntity] and [ApiAccess(EntityAccess.Read)] |
[Property<T>("Value", ReadOnly = true)] |
[Property<T>("Value")] and [ApiAccess(PropertyAccess.ReadOnly)] |
[ReferenceProperty(..., ReadOnly = true)] |
[ReferenceProperty(...)] and [ApiAccess(PropertyAccess.ReadOnly)] |
[VirtualReferenceProperty(..., ReadOnly = true)] |
[VirtualReferenceProperty(...)] and [ApiAccess(PropertyAccess.ReadOnly)] |
Update all Core packages together and rebuild models.
Metadata keeps derived ReadOnly summaries. Business-rule ReadOnly(...) and Hidden(...) keep their existing meaning.
ApiReadOnlyFilter and ApiReadOnlyRules are replaced by generated ApiAccessRules.
Update direct integrations with these types. Update grants that relied on Create being required for field writes.
An existing read-only entity maps to EntityAccess.Read; enabling Update is a separate behavior change.
Build error BVG010 means the enum does not match its target. BVG011 means an undefined enum value.