Resource Registry — API Access & Query Templates

Query Template Management — base path /query-templates

Authorization & Token Selection

| Action | HTTP | Path | Query Parameters | IS-M / Infra-M | IS-Admin | Ctx-M | IS-Editor | IS-Contrib | IS-Member | |——–|——|——|——————|:————–:|:——–:|:—–:|:———:|:———-:|:———:| | List | GET | /query-templates | limit, offset, metadataPolicy | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Execute JSON Query | QUERY | /query-templates (POST /query-templates/query fallback) | limit, offset, metadataPolicy | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Create/Update | PUT | /query-templates/{name} | metadataPolicy | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | | Read | GET | /query-templates/{name} | metadataPolicy | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Execute | QUERY | /query-templates/{name} (POST /query-templates/{name}/query fallback) | limit, offset, polymorphic, hierarchical, metadataPolicy, contextsPolicy, membershipScope | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Delete | DELETE | /query-templates/{name} | None | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |

Token Scope Rule:

| Operation Group | Token must be issued for | |—————-|—————————| | List, Execute JSON Query, Read | No specific target Context is required; authorization is evaluated from the token role | | Create/Update, Delete | No specific target Context is required; authorization is evaluated from the token role (requires IS-M, Infra-M, or IS-Admin) | | Execute | The operational Context resolved from the token’s current path or, when no current path matches, from a valid previousPaths entry |

HTTP Contract

| Action | Additional Request Headers | Response Headers | Success HTTP Code | Error HTTP Code | |——–|—————————-|——————|——————-|—————–| | List | Accept | Content-Type, Link, X-Warning | 200 OK | 403 Forbidden | | Execute JSON Query | Content-Type, Accept | Content-Type, Link, X-Warning | 200 OK | 400 Bad Request, 403 Forbidden | | Create/Update | Content-Type, Accept | Content-Type, X-Warning | 201 Created / 200 OK | 400 Bad Request, 403 Forbidden, 409 Conflict | | Read | Accept | Content-Type, Link, X-Warning | 200 OK | 403 Forbidden, 404 Not Found | | Execute | Content-Type, Accept | Content-Type, Link, X-Warning, conditional X-Result-Scope / X-Resolved-Context-Path | 200 OK | 400 Bad Request, 403 Forbidden, 404 Not Found | | Delete | None | X-Warning | 204 No Content | 403 Forbidden, 404 Not Found |

Operational Notes

  • Global List Semantics: GET /query-templates and its /access mirror list the global Query Template collection for every operational role; the token Context is not a visibility boundary. Pagination is applied using limit and offset. When metadataPolicy includes metadata, identity fields are visible to IS-M, Infra-M, and IS-Admin and redacted for every other role. Serialization is all-or-nothing: an unreadable row fails the request instead of producing a partial successful page.

  • Global Definition Query Semantics: QUERY /query-templates and its /access mirror search the global Query Template definitions, not the instances returned by executing a stored template. They accept a required JSON QBE object and support the canonical operators and _emit rules. Full metadata and projected metadata-identity aliases are visible to IS-M, Infra-M, and IS-Admin and redacted for every other role; metadataPolicy is ignored with X-Warning when _emit determines the response shape. Result serialization is fail-fast rather than returning a silently incomplete page.

  • Target Limitation (Instances Only): Although the JSON Query engine supports querying Contexts, Type Schemas, Query Templates, and Instances, the Query Template mechanism is by design strictly restricted to Instances. Any query saved within a template is implicitly executed to find instances. Consequently, the root "type" in a saved template must always specify a valid Entity or Relation type (e.g., Resource, EService). Query templates cannot be used to save queries targeting Contexts, Type Schemas, or other Query Templates.

  • Payload Consistency: name in the PUT path parameter must match the name field in the JSON body. A Query Template definition is a closed representation, as a Type definition is: a member it does not define returns 400 Bad Request (in the definition or in a TemplateVariable), description is mandatory, and type, when present, must be QueryTemplate. The system fields are not such members: supertypes, id, and metadata on the definition, and type and supertypes on a TemplateVariable, are accepted. A path/body name mismatch, a name outside the grammar, or any of these violations returns 400 Bad Request.

  • Public name identity and representation id: The exact, case-sensitive name is the Query Template’s stable public identity and sole routing key, with the same status that name has for a Type. The id field in the JSON representation is its global UUID, never an alternative public identity or URL key. If id is omitted or null during creation, the backend generates one. A supplied UUID that is already in use, by another Query Template or by any other registry element, produces 409 Conflict, following the registry-wide UUID ownership rule. During an update, name resolves the target and an explicitly supplied id is a consistency assertion that must match the persisted UUID, otherwise the request is rejected with 409 Conflict: the request is well formed and conflicts only with the persisted state.

  • Versioned Upsert Semantics: PUT /query-templates/{name} creates the Query Template when the name is absent and otherwise compares the submitted definition with the persisted one. The comparison covers the complete definition except the identity/audit fields id and metadata and the system fields type and supertypes; an omitted optional member equals its default value, and numbers are compared by value (1 equals 1.0). A missing or malformed version, or a changelog whose highest entry is not that version, returns 400 Bad Request: as for a Type, every new version carries its own changelog entry. Roles other than IS-M, Infra-M, and IS-Admin cannot create or update templates; any such attempt returns 403 Forbidden regardless of whether the template already exists.

    | Persisted state | Outcome | |—————–|———| | Name absent | Created: 201 Created | | Submitted version higher than the persisted one | Updated: 200 OK, when the advancement satisfies Version Advancement below and the submitted changelog repeats every persisted entry unchanged; otherwise 409 Conflict | | Same version, identical definition | No-op: 200 OK; the persisted Query Template, its metadata included, is unchanged | | Same version, different definition | 409 Conflict: a changed definition requires a higher version | | Submitted version lower than the persisted one | 409 Conflict: the registry never replaces a definition with an older one |

    Every successful outcome returns the persisted representation. A component that installs its Query Templates at start-up therefore submits the same definition on every start: the first submission creates or updates it, the following ones are no-ops, and a 409 Conflict tells an outdated component that a newer definition is already installed. (Contrast with Type definition: Types forbid online structural updates altogether, while a Query Template is updated online by submitting a higher version.)

  • Version Advancement: A version has the form major.minor.patch, for example 2.4.1. Advancing one component resets the less significant ones to 0:

    | Advancement | Meaning | From 2.4.1 | |————-|———|————–| | patch | The definition is corrected or reworded; callers are not affected | 2.4.2 | | minor | The definition changes in a way that existing callers keep working with | 2.5.0 | | major | The definition changes in a way that can break existing callers | 3.0.0 |

    An update must advance version at least as far as the change requires. The server classifies the difference between the submitted and the persisted definition and enforces only the minimum it can establish from the definition itself. It does not require the exact version a human reviewer would choose: any version at or above the required minimum is accepted, so a deployment may skip intermediate versions (from 2.4.1, a change that requires a minor advancement accepts 2.5.0, 2.7.3, or 3.0.0, but not 2.4.2).

    | Difference from the persisted definition | Required advancement | Lowest accepted version from 2.4.1 | |——————————————|———————-|————————————–| | Descriptions only (of the template or of its variables), or no change other than the new version and its changelog entry | At least patch | 2.4.2 | | The template body, with the same variables and the same result shape | At least patch | 2.4.2 | | A new variable with required=false; a variable changed from required=true to required=false; a variable constraint removed; a defaultValue changed | At least minor | 2.5.0 | | A variable removed or renamed; a variable propertyType changed; a new variable with required=true, or a variable changed to required=true; a variable constraint added or modified; the result shape changed | Major | 3.0.0 |

    The result shape is the root type of the template and its _emit projection; any change to either counts, a narrower Type included. A renamed variable is a removed variable plus a new one. When a submission contains several differences, the highest required advancement applies. An insufficient advancement returns 409 Conflict, and the message of the error body names the persisted version, the submitted version, and the lowest accepted version.

    The server cannot tell whether a changed template body is a correction or an intended change of the result. The author chooses: a patch advancement for a correction or an equivalent rewrite, a minor advancement when the same call deliberately returns a different result. A major change breaks every caller that still uses the previous variables or result shape, and callers that are updated at different times coexist only when the changed definition is published under a new name.

  • Unique Name: The registry holds at most one Query Template for each exact, case-sensitive name, under concurrent requests too. Concurrent submissions for the same name follow the general Transactional Execution & Concurrency Contract: one commits, a conflicting one returns 409 Conflict, and repeating the same request then falls into one of the outcomes above.

  • Global Point Read Semantics: GET /query-templates/{name} and its /access mirror resolve the exact, case-sensitive global Query Template name for every operational role without applying token-Context visibility. metadataPolicy=none|root|all controls metadata inclusion; when metadata is present, createdBy and lastUpdateBy are visible to IS-M, Infra-M, and IS-Admin and redacted for every other role. A name that identifies no Query Template returns 404 Not Found, whether or not it follows the name grammar: the grammar is enforced only when a definition is saved. Successful responses include the canonical name-addressed Content-Location and a Link: rel="collection" to the Query Template collection of the same surface (/query-templates, or /access/query-templates for the mirror).

  • Definition visibility vs. execution state: Listing, querying, or reading Query Template definitions is independent of the token Context and its effectiveState. Executing a template is an instance query and therefore applies the same token-path resolution, visibility, and effectiveState barrier as QUERY /instances. A token carrying a valid previous path executes in the resolved current Context and returns X-Result-Scope: previous-path plus X-Resolved-Context-Path; the management and /access execution surfaces behave identically. When the role/state matrix disables instance reads for the caller, execution returns 403 Forbidden. Administrative roles retain the state override defined by the matrix. Hierarchical execution by a non-administrative role skips non-active descendants and reports X-Result-Scope: state-filtered when applicable.

  • Parameter Validation: Template variables use the complete declaration and substitution contract in Data Representation — TemplateVariable Contract. Saving validates declarations and the query produced by their mandatory defaults; execution validates supplied values before recursive whole-node substitution. Every save-time validation failure (a declaration that violates the contract, an undeclared or unused variable, an invalid default, a root type that is not an Entity or Relation Type) returns 400 Bad Request.

  • Execute Payload: The optional request body for QUERY /query-templates/{name} contains a JSON object of template-variable substitutions and, when present, must use Content-Type: application/json. An absent or empty body uses defaults only for variables with required=false. Omission of a required=true variable, explicit null, a type or constraint violation, malformed JSON, or a non-object JSON value produces 400 Bad Request. Undeclared input keys are ignored with X-Warning.

  • Hierarchical Execution: hierarchical in Execute expands the search boundary and is available to every operational role (see hierarchical parameter). IS-M, Infra-M, IS-Admin, and Ctx-M retain unrestricted descendant visibility; other roles use the active-only hierarchical channel, omit non-active descendant memberships, and receive X-Result-Scope: state-filtered when the subtree contains a non-active descendant Context or a membership is omitted from a contexts map.

  • Execute Visibility and Privacy: Execution uses the same instance-query engine and role-derived visibility directives as QUERY /instances. After template-variable substitution, direct, nested, and logical predicates involving metadata.createdBy or metadata.lastUpdateBy are evaluated against the caller-visible logical representation. IS-M, Infra-M, and IS-Admin compare stored identities; every other role compares "[REDACTED]", whether the predicate value is fixed in the template or supplied through a variable. A fixed real identity therefore produces no match for a caller who cannot see it, while that same template remains executable and may be parameterized with "[REDACTED]". Projection follows the same view. When contextsPolicy=root|all includes membership maps, membershipScope independently selects the token Context subtree or, for authorized universal roles, the global membership view. Omitting memberships outside an explicitly requested subtree emits no X-Result-Scope token. Projection queries preserve the canonical _emit precedence and report ignored enrichment parameters through X-Warning.

  • Permanent Exact-Name Delete: DELETE /query-templates/{name} permanently and atomically removes the Query Template identified by its exact, case-sensitive global name and makes that name reusable. IS-M, Infra-M, and IS-Admin may delete; token Context does not restrict the target. The operation accepts neither a request body nor query parameters. Supplied query parameters are ignored with X-Warning; an unknown or already deleted exact name returns 404 Not Found.

Access API — base path /access

Read-only facade that mirrors the readable collection methods and adds query execution endpoints.

Architectural Note on Dual-Paths (Network-Level Exposure): The existence of duplicated read-only endpoints (e.g., GET /instances/{type} vs GET /access/instances/{type}) with identical authorization rules serves a critical infrastructure purpose: network-level segregation. The D4Science security model dictates that all write-capable endpoints (e.g., /instances, /contexts) are restricted solely to internal microservice traffic. Conversely, the /access facade (along with its query execution endpoints) is the only branch exposed to the external internet. This architectural split ensures external clients can discover and read instances but cannot physically reach the write API surfaces.

Important — DB-Level Read-Only Restriction: All query execution operations initiated through this facade (JSON queries and Query Template execution via /access) are strictly read-only: they can only select data, and no query form accepted by the facade can modify it.

All endpoints in this class that mirror existing management endpoints (/contexts, /types, /instances, /query-templates) share the same authorization rules as their counterparts.

Normative Mirror-Parity Rule: For mirrored endpoints, status-code semantics are contractually identical to their core counterparts (including 403 vs 404 distinction where applicable). The facade exists for network exposure and read-only separation, not for semantic rewriting. Mirrors also accept the same query parameters, emit the same response headers (Content-Location, Link, X-Warning, X-Result-Scope, X-Resolved-Context-Path), and support the same POST {path}/query fallback as their core counterparts.

Contexts, Types, Query Templates (mirrors)

| Action | HTTP | Path | IS-M / Infra-M | IS-Admin | Ctx-M | IS-Editor | IS-Contrib | IS-Member | |——–|——|——|:-:|:-:|:-:|:-:|:-:|:-:| | List Contexts | GET | /access/contexts | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Execute Context JSON Query | QUERY | /access/contexts | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Read Context | GET | /access/contexts/{context-uuid} | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Read Current Context | GET | /access/contexts/@current | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Read Context History | GET | /access/contexts/{context-uuid}/history | ✅ | ✅ | ⚠️ | ❌ | ❌ | ❌ | | Execute Type JSON Query | QUERY | /access/types | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Read Type | GET | /access/types/{type-name} | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | List Query Templates | GET | /access/query-templates | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Execute Query Template JSON Query | QUERY | /access/query-templates | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Read Query Template | GET | /access/query-templates/{name} | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Execute Query Template | QUERY | /access/query-templates/{name} | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |

Instances (mirrors)

| Action | HTTP | Path | IS-M / Infra-M | IS-Admin | Ctx-M | IS-Editor | IS-Contrib | IS-Member | |——–|——|——|:-:|:-:|:-:|:-:|:-:|:-:| | List Instances | GET | /access/instances/{type} | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Execute Instance JSON Query | QUERY | /access/instances | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Exists | HEAD | /access/instances/{type}/{instance-uuid} | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Read Instance | GET | /access/instances/{type}/{instance-uuid} | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | List Instance Contexts | GET | /access/instances/{type}/{instance-uuid}/contexts | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |

Exists is the bodyless view of Read Instance, with the same semantics as HEAD /instances/{type}/{instance-uuid}.

Token Selection (Quick Rule)

| Operation Group | Token must be issued for | |—————-|—————————| | Mirror reads and JSON Queries (/access/contexts, /access/types, /access/instances, /access/query-templates) | Same authorization logic as mirrored endpoints (e.g., Token Context acts as visibility scope for Instances, but acts merely as role-bearer for Types and Templates) | | Template execution via /access | Token Context acts as visibility scope |

Notes for JSON queries: