xRegistry HTTP Binding 🔗

Abstract 🔗

This specification defines an HTTP protocol binding for the xRegistry specification. This document will include just the HTTP-specific details and semantics, leaving the core specification to define the xRegistry generic processing model and semantics that apply to all protocols.

Table of Contents 🔗

Notations and Terminology 🔗

Notational Conventions 🔗

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

For clarity, OPTIONAL attributes (specification-defined and extensions) are OPTIONAL for clients to use, but the servers' responsibility will vary. Server-unknown extension attributes MUST be silently stored in the backing datastore. Specification-defined, and server-known extension attributes, MUST generate an error if the corresponding feature is not supported or enabled. However, as with all attributes, if accepting the attribute results in a bad state (such as exceeding a size limit, or results in a security issue), then the server MAY choose to reject the request.

In the pseudo JSON format snippets ? means the preceding item is OPTIONAL, * means the preceding item MAY appear zero or more times, and + means the preceding item MUST appear at least once. The presence of the # character means the remaining portion of the line is a comment. Whitespace characters in the JSON snippets are used for readability and are not normative.

When HTTP query parameters are discussed, they are presented as ?<NAME> where <NAME> is the name of the query parameter.

See the core specification for details about the use of <...> substitution values.

Terminology 🔗

See the core specification for the list of xRegistry defined terms that might be used.

HTTP Binding Overview 🔗

HTTP API Patterns 🔗

This specification defines the following base API patterns:

/                                                # Access the Registry
/capabilities                                    # Access features enabled
/capabilitiesoffered                             # Access available features
/model                                           # Access full model definitions
/modelsource                                     # Access model customizations
/export                                          # Retrieve Registry as a doc
/<GROUPS>                                        # Access a Group Type
/<GROUPS>/<GID>                                  # Access a Group
/<GROUPS>/<GID>/<RESOURCES>                      # Access a Resource Type
/<GROUPS>/<GID>/<RESOURCES>/<RID>                # Default Version of Resource
/<GROUPS>/<GID>/<RESOURCES>/<RID>/meta           # Access a Resource's metadata
/<GROUPS>/<GID>/<RESOURCES>/<RID>/versions       # Versions of a Resource
/<GROUPS>/<GID>/<RESOURCES>/<RID>/versions/<VID> # Access Version of Resource

While these APIs are shown to be at the root path of a host, implementations MAY choose to prefix them as necessary. However, the same prefix MUST be used consistently for all APIs in the same Registry instance.

If an OPTIONAL HTTP path is not supported by an implementation, then any use of that API MUST generate an error (api_not_found).

If an HTTP method is not supported for a supported HTTP path, then an error (action_not_supported) MUST be generated.

Implementations MAY support extension APIs, however, the following rules apply:

For example, a new API with an HTTP path of /my-api is allowed, but APIs with /model/my-api or /name HTTP paths are not.

Adherence to HTTP Standards 🔗

This specification leans on the RFC9110 HTTP Semantics model with the RFC5789 PATCH extension. The following key aspects are called out to help understand the overall pattern of the APIs:

No-Code Servers 🔗

In the core specification there is a discussion about "no-code servers". In the case of HTTP, simple file servers SHOULD support exposing Resources where the HTTP body response contains the Resource's domain-specific "document" as well exposing the serialization of the Resource's xRegistry metadata via the $details suffix on the URL path. This can be achieved by creating a secondary, sibling, file on disk with $details at the end of its filename.

Registry HTTP APIs 🔗

This section mainly focuses on the successful interaction patterns of the APIs. For example, most examples will show an HTTP "200 OK" as the response. Each implementation MAY choose to return a more appropriate response based on the specific situation. For example, in the case of an authentication error the server could return 401 Unauthorized.

The following sections define the API in more detail.

Entity Processing Rules 🔗

Rather than repeating the processing rules for PATCH, POST and PUT, for each type of xRegistry entity or Registry collection, the overall pattern is defined once in this section and any entity-, or collection-specific rules will be detailed in the appropriate section in the specification.

Creating or Updating Entities 🔗

This defines the general rules for how to update entities.

Creating or updating entities MAY be done using HTTP PUT, PATCH or POST methods:

See the Request Flags section for the list of flags/query parameters that MAY be used for each API.

The PUT variant MUST adhere to the following:

The PATCH variant when directed at a single entity, MUST adhere to the PUT semantics defined above with the following exceptions:

The POST variant when directed at a single entity other than a Resource, MUST adhere to the following:

The POST variant when directed at a Resource entity, MUST adhere to the following:

The PATCH variant when directed at an xRegistry collection, MUST adhere to the following:

The POST variant when directed at an xRegistry collection MUST adhere to the following:

The processing of each individual entity follows the same set of rules:

Resources and Versions have the following additional rules:

A successful response MUST return the same response as a GET to the entity (or entities) processed, showing their current representation in the same format ($details variant or not) as the request, with the following exceptions:

Otherwise an HTTP 200 OK without an HTTP Location header MUST be returned.

Note that the response MUST be generated applying the semantics of any request flags specified in the request URL (e.g. ?inline).

xRegistry Root HTTP Header 🔗

All API responses, including errors, SHOULD include a Link HTTP header of the form:

Link: <URL-TO-XREGISTRY-ROOT>;rel=xregistry-root

Where URL-TO-XREGISTRY-ROOT is the URL to the root of the current xRegistry instance.

This allows for client-side response processing to unambiguously know the base URL of the Registry from which the response came without needing to know the request URL or attempting to determine the URL from the response payload.

Examples:

Link: <https://myregistry.example.com>;rel=xregistry-root

HTTP-Specific Attribute Processing Rules 🔗

self Attribute 🔗

In addition to the core specification's definition of self, the following HTTP-specific rules apply:

labels Attribute 🔗

In addition to the core specification's definition of labels, the following HTTP-specific rules apply:

contenttype Attribute 🔗

In addition to the core specification's definition of contenttype, the following HTTP-specific rules apply:

<RESOURCE> Attribute 🔗

In addition to the core specification's definition of <RESOURCE>, the following HTTP-specific rules apply:

<RESOURCE>base64 Attribute 🔗

Pagination 🔗

Since xRegistry collections (i.e. the <COLLECTION> attribute) could be too large to retrieve in a single request, when retrieving a collection, the client MAY request a subset by using the pagination specification. Likewise, the server MAY choose to return a subset of the collection using the same mechanism defined in that specification even if the request didn't ask for pagination. The pagination specification MUST only be used when the request is directed at a collection, not at its owning entity (such as the root of the Registry, or at an individual Group or Resource).

In the remainder of this specification, the presence of the Link HTTP header indicates the use of the pagination specification MAY be used for that API.

HTTP OPTIONS Method 🔗

A server MAY support clients querying the list of supported HTTP methods for any supported API. The request MUST be of the form:

OPTIONS <PATH>

A successful response MUST be of the form:

HTTP/1.1 200 OK
Allow: <METHODS>
Access-Control-Allow-Methods: <METHODS>

Where:

Examples:

Retrieve supported list of HTTP method at the root of the Registry:

OPTIONS /
HTTP/1.1 200 OK
Allow: GET, OPTIONS
Access-Control-Allow-Methods: GET, OPTIONS

Registry Entity 🔗

GET / 🔗

A server MAY support clients retrieving Registry Entity via an HTTP GET directed to the Registry Entity.

See Registry Entity for more information.

The request MUST be of the form:

GET /

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  ... Registry entity excluded for brevity ...
}

Examples:

Retrieve a Registry that has 2 types of Groups (endpoints and schemagroups):

GET /
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "specversion": "1.0-rc2",
  "registryid": "myRegistry",
  "self": "https://example.com/",
  "xid": "/",
  "epoch": 1,
  "createdat": "2024-04-30T12:00:00Z",
  "modifiedat": "2024-04-30T12:00:01Z",

  "endpointsurl": "https://example.com/endpoints",
  "endpointscount": 42,

  "schemagroupsurl": "https://example.com/schemagroups",
  "schemagroupscount": 1
}

PATCH and PUT / 🔗

A server MAY support clients updating the Registry entity via an HTTP PATCH or PUT directed to the Registry entity.

The processing of these APIs is defined in the Creating or Updating Entities section.

The request MUST be of the form:

PUT /
Content-Type: application/json; charset=utf-8
or
PATCH /
Content-Type: application/json; charset=utf-8

{
  ... Registry entity excluded for brevity ...
}

Where:

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  .. Registry entity excluded for brevity ...
}

Examples:

Updating a Registry's metadata:

PUT /
Content-Type: application/json; charset=utf-8

{
  "registryid": "myRegistry",
  "name": "My Registry",
  "description": "An even cooler registry!"
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "specversion": "1.0-rc2",
  "registryid": "myRegistry",
  "self": "https://example.com/",
  "xid": "/",
  "epoch": 2,
  "name": "My Registry",
  "description": "An even cooler registry!",
  "createdat": "2024-04-30T12:00:00Z",
  "modifiedat": "2024-04-30T12:00:01Z",

  "endpointsurl": "https://example.com/endpoints",
  "endpointscount": 42,

  "schemagroupsurl": "https://example.com/schemagroups",
  "schemagroupscount": 1
}

POST / 🔗

A server MAY support clients updating or creating multiple Groups of varying types via an HTTP POST directed to the Registry entity. This API is very similar to the POST /<GROUPS> API, except that the HTTP body MUST be a map of Group types as shown below:

The request MUST be of the form:

POST /
Content-Type: application/json; charset=utf-8

{
  # Repeat for each Group type that has a Group to be created or updated
  "<GROUPS>": {
    "<GROUPS>id": {
      ... Group entity excluded for brevity ...
    } *
  } *
}

Notice the format is almost the same as what a PUT / would look like if the request wanted to update the Registry's attributes and define a set of Groups, but without the Registry's attributes. This allows for an update of the specified Groups without modifying the Registry's attributes.

A request that isn't a map of Group types (e.g. it contains other Registry level attributes) MUST generate an error (groups_only).

The response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "<GROUPS>": {
    "<GROUPS>id": {
      ... Group entity excluded for brevity ...
    } *
  } *
}
}

Where:

Examples:

Creating 4 Groups of 2 different Group types.

POST /
Content-Type: application/json; charset=utf-8

{
  "endpoints": {
    "endpoint1": { ... Group endpoint1 excluded for brevity ... },
    "endpoint2": { ... Group endpoint2 excluded for brevity ... }
  },
  "schemagroups": {
    "schemagroup1": { ... Group schemagroup1 excluded for brevity ... },
    "schemagroup2": { ... Group schemagroup2 excluded for brevity ... }
  }
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "endpoints": {
    "endpoint1": { ... Group endpoint1 excluded for brevity ... },
    "endpoint2": { ... Group endpoint2 excluded for brevity ... }
  },
  "schemagroups": {
    "schemagroup1": { ... Group schemagroup1 excluded for brevity ... },
    "schemagroup2": { ... Group schemagroup2 excluded for brevity ... }
  }
}

GET /export 🔗

The GET /export API MUST be an alias for GET /?doc&inline=*,capabilities,modelsource. If this path is supported, it MUST NOT support any HTTP update methods. This API was created:

Request Flags MAY be included, if supported, and any ?inline flag specified MUST override the default value defined above.

A request MUST be of the form:

GET /export

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  ... Registry entity, and nested collections, excluded for brevity ...
}

Registry Capabilities 🔗

GET /capabilities 🔗

A server SHOULD support clients retrieving the set of capabilities(features) it supports via an HTTP GET directed to the stand-alone capabilities map.

The request MUST be of the form:

GET /capabilities

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ ... Capabilities map excluded for brevity ... }

Examples:

GET /capabilities
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "apis": [
    "/capabilities", "/export", "/model", "/modelsource"
  ],
  "flags": [
    "binary", "collections", "doc", "epoch", "filter", "ignore", "inline",
    "setdefaultversionid", "sort", "specversion"
  ],
  "ignores": [ "capabilities", "defaultversionid", "defaultversionsticky",
    "epoch", "id", "modelsource", "readonly"
  ],
  "mutable": [ "capabilities", "entities", "model" ],
  "pagination": false,
  "shortself": false,
  "specversions": [ "1.0-rc2" ],
  "stickyversions": true
}

GET /capabilitiesoffered 🔗

If a server supports clients updating its capabilities, then it SHOULD support clients retrieving the set of valid offered capabilities it supports via an HTTP GET directed to the stand-alone capabilitiesoffered map.

The request MUST be of the form:

GET /capabilitiesoffered

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ ... Capabilities offering map excluded for brevity ... }

Examples:

GET /capabilitiesoffered
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "apis": {
    "type": "array",
    "item": {
      "type": "string"
    },
    "enum": [ "/capabilities", "/capabilitiesoffered", "/export", "/model",
       "/modelsource" ]
  },
  "flags": {
    "type": "array",
    "item": {
      "type": "string"
    },
    "enum": [ "collections", "doc", "epoch", "filter", "ignore", "inline",
       "setdefaultversionid", "sort", "specversion" ]
  },
  "ignores": {
    "type": "array",
    "item": {
      "type": "string"
    },
    "enum": [ "capabilities", "defaultversionid", "defaultversionsticky",
      "epoch", "id", "modelsource", "readonly" ]
  },
  "pagination": {
    "type": "boolean",
    "enum": [ false, true ]
  },
  "shortself": {
    "type": "boolean",
    "enum": [ false, true ]
  },
  "specversions": {
    "type": "array",
    "item": {
      "type": "string"
    },
    "enum": [ "1.0-rc2" ]
  },
  "stickyversions": {
    "type": "boolean",
    "enum": [ true ]
  },
  "versionmodes": {
    "type": "array",
    "item": {
      "type": "string"
    },
    "enum": [ "manual" ]
  }
}

PATCH and PUT /capabilities 🔗

A server MAY support clients updating its supported capabilities (features) via an HTTP PATCH or PUT directed to the stand-alone capabilities map.

A PUT MUST be interpreted as a request to update the entire set of capabilities and any missing capability MUST be interpreted as a request to reset it to its default value.

A PATCH is used to update a subset of capabilities. Each capability included MUST be fully specified, and only those specified in the request MUST be fully replaced by the incoming values. In other words, PATCH is done at a capability level, not any deeper within the JSON structure.

See Updating the Capabilities of a Server for more information.

The request MUST be of the form:

PATCH /capabilities
Content-Type: application/json; charset=utf-8
or
PUT /capabilities
Content-Type: application/json; charset=utf-8

{ ... Capabilities map excluded for brevity...  }

Where:

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ ... Capabilities map excluded for brevity ... }

Any change to the configuration of the server that is not supported MUST result in an error (capability_error) and no changes applied. Likewise, any unknown capability keys specified MUST generate an error (capability_error).

Note: per the Updating the Capabilities of a Server section, the semantic changes MUST NOT take effect until after the processing of the current request is completed, even though the response MUST show the requested changes.

Examples:

PATCH /capabilities

{
  "shortself": true
}
{
  "apis": [
    "/capabilities", "/export", "/model", "/modelsource"
  ],
  "flags": [
    "binary", "collections", "doc", "epoch", "filter", "ignore", "inline",
    "setdefaultversionid", "sort", "specversion"
  ],
  "ignores": [
    "capabilities", "defaultversionid", "defaultversionsticky", "epoch",
    "id", "modelsource", "readonly"
  ],
  "mutable": [ "capabilities", "entities", "model" ],
  "pagination": false,
  "shortself": true,
  "specversions": [ "1.0-rc2" ],
  "stickyversions": true
}

Registry Model 🔗

GET /model 🔗

A server MAY support clients retrieving its full model definition via an HTTP GET directed to the stand-lone model entity.

The request MUST be of the form:

GET /model

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ ... Model definition excluded for brevity ... }

To retrieve the model as part of the response to retrieving the Registry entity, use the Inline Flag with a value of model.

Note that the /model API is a read-only API.

GET /modelsource 🔗

A server MAY support clients retrieving the client-provided model definition used to define the current model via an HTTP GET directed to the stand-alone modelsource entity.

The request MUST be of the form:

GET /modelsource

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ ... Model definition excluded for brevity ... }

To retrieve the modelsource as part of the response to retrieving the Registry entity, use the Inline Flag with a value of modelsource.

PUT /modelsource 🔗

A server MAY support clients updating its model definition via an HTTP PUT directed to the stand-alone modelsource entity.

The request MUST be of the form:

PUT /modelsource
Content-Type: application/json; charset=utf-8

{ ... Model definition excluded for brevity ... }

To update the modelsource as part of a request to update the Registry entity, you can include the attribute as part of the PUT / request.

Group Entity 🔗

GET /<GROUPS> 🔗

A server MAY support clients retrieving a Group collection via an HTTP GET directed to the Registry's <GROUPS> collection URL.

The request MUST be of the form:

GET /<GROUPS>

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Link: <URL>;rel=next;count=<UINTEGER> ?

{
  "<KEY>": {                                       # <GROUP>id
    ... Group entity excluded for brevity ...
  } *
}

Examples:

Retrieve all entities in the endpoints Group collection:

GET /endpoints
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Link: <https://example.com/endpoints&page=2>;rel=next;count=100

{
  "ep1": {
    "endpointid": "ep1",
    "self": "https://example.com/endpoints/ep1",
    "xid": "/endpoints/ep1",
    "epoch": 1,
    "name": "A cool endpoint",
    "createdat": "2024-04-30T12:00:00Z",
    "modifiedat": "2024-04-30T12:00:01Z",

    "messagesurl": "https://example.com/endpoints/ep1/messages",
    "messagescount": 5
  },
  "ep2": {
    "endpointid": "ep2",
    "self": "https://example.com/endpoints/ep2",
    "xid": "/endpoints/ep2",
    "epoch": 3,
    "name": "Redis Queue",
    "createdat": "2024-04-30T12:00:00Z",
    "modifiedat": "2024-04-30T12:00:01Z",

    "messagesurl": "https://example.com/endpoints/ep2/messages",
    "messagescount": 1
  }
}

Notice that the Link HTTP header is present, indicating that there is a second page of results that can be retrieved via the specified URL, and that there are a total of 100 items in this collection.

PATCH and POST /<GROUPS> 🔗

A server MAY support clients creating/updating multiple Groups in a Group collection via an HTTP PATCH or POST directed to the Registry's <GROUPS> collection URL.

The processing of these APIs is defined in the Creating or Updating Entities section.

The request MUST be of the form:

PATCH /<GROUPS>
Content-Type: application/json; charset=utf-8
or
POST /<GROUPS>
Content-Type: application/json; charset=utf-8

{
   "<KEY>": {                                      # <GROUP>id
     ... Group entity excluded for brevity ...
  } *
}

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
   "<KEY>": {                                      # <GROUP>id
     ... Group entity excluded for brevity ...
  } *
}

Examples:

POST /endpoints
Content-Type: application/json; charset=utf-8

{
  "ep1": {
    "endpointid": "ep1",
    ... remainder of ep1 definition excluded for brevity ...
  },
  "ep2": {
    "endpointid": "ep2",
    ... remainder of ep2 definition excluded for brevity ...
  }
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "ep1": {
    "endpointid": "ep1",
    ... remainder of ep1 definition excluded for brevity ...
  },
  "ep2": {
    "endpointid": "ep2",
    ... remainder of ep2 definition excluded for brevity ...
  }
}

DELETE /<GROUPS> 🔗

A server MAY support clients deleting one or more Groups from a Group collection via an HTTP DELETE directed to the Registry's <GROUPS> collection URL.

The processing of this API is defined in the Deleting Entities section of the core specification.

The request MUST be of the form:

DELETE /<GROUPS>

{
   "<KEY>": {                            # <GROUP>id
     "epoch": <UINTEGER> ?
   } *
} ?

A successful response MUST be of the form:

HTTP/1.1 200 OK
or
HTTP/1.1 204 No Content

Examples:

Delete multiple Groups:

DELETE /endpoints

{
  "ep1": {
    "epoch": 5
  },
  "ep2": {}
}
HTTP/1.1 204 No Content

Notice that the epoch value for ep1 will be verified prior to the delete, but no such check will happen for ep2.

GET /<GROUPS>/<GID> 🔗

A server MAY support clients retrieving a Group via an HTTP GET directed to the Group entity.

The request MUST be of the form:

GET /<GROUPS>/<GID>

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  ... Group entity excluded for brevity ...
}

Examples:

Retrieve a single endpoints Group:

GET /endpoints/ep1
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "endpointid": "ep1",
  "self": "https://example.com/endpoints/ep1",
  "xid": "/endpoints/ep1",
  "epoch": 1,
  "name": "myEndpoint",
  "createdat": "2024-04-30T12:00:00Z",
  "modifiedat": "2024-04-30T12:00:01Z",

  "messagesurl": "https://example.com/endpoints/ep1/messages",
  "messagescount": 5
}

PATCH and PUT /<GROUPS>/<GID> 🔗

A server MAY support clients creating or updating a Group in a Group collection via an HTTP PATCH or PUT directed to the Group entity.

The processing of these APIs is defined in the Creating or Updating Entities section.

The request MUST be of the form:

PATCH /<GROUPS>/<GID>
Content-Type: application/json; charset=utf-8
or
PUT /<GROUPS>/<GID>
Content-Type: application/json; charset=utf-8

{ ... Group entity excluded for brevity ... }

The response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ ... Group entity excluded for brevity ... }

Examples:

Create a new Endpoint:

PUT /endpoints/ep1
Content-Type: application/json; charset=utf-8

{
  "endpointid": "ep1",
  ... remainder of Endpoint 'ep1' definition excluded for brevity ...
}
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Location: https://example.com/endpoints/ep1

{
  "endpointid": "ep1",
  ... remainder of Endpoint 'ep1' definition excluded for brevity ...
}

POST /<GROUPS>/<GID> 🔗

A server MAY support clients creating/updating one or more Resources, of varying Resource types, within the specified Group via an HTTP POST to the owning Group.

The processing of this API is defined in the Creating or Updating Entities section - see the discussion of the POST <PATH-TO-ENTITY> variant.

A request that isn't a map of Resource types (e.g. it contains other Group level attributes) MUST generate an error (resources_only).

The request MUST be of the form:

POST /<GROUPS>/<GID>
Content-Type: application/json; charset=utf-8

{
  "<RESOURCES>": {
    "<KEY>": {                            # <RESOURCE>id
      ... Resource entity excluded for brevity ...
    } *
  } *
}

The response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "<RESOURCES>": {
    "<KEY>": {                            # <RESOURCE>id
      ... Resource entity excluded for brevity ...
    } *
  } *
}

Examples:

Create a Message and a Schema Resource under Group g1:

POST /groups/g1
Content-Type: application/json; charset=utf-8

{
  "messages": {
    "messageid": "msg1",
    ... remainder of msg1 definition excluded for brevity ...
  },
  "schemas": {
    "schemaid": "schema1",
    ... remainder of schema1 definition excluded for brevity ...
  }
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "messages": {
    "messageid": "msg1",
    ... remainder of msg1 definition excluded for brevity ...
  },
  "schemas": {
    "schemaid": "schema1",
    ... remainder of schema1 definition excluded for brevity ...
  }
}

DELETE /<GROUPS>/<GID> 🔗

A server MAY support clients deleting a Group via an HTTP DELETE directed to the Group entity.

The processing of this API is defined in the Deleting Entities section of the core specification.

The request MUST be of the form:

DELETE /<GROUPS>/<GID>

A successful response MUST be of the form:

HTTP/1.1 200 OK
or
HTTP/1.1 204 No Content

Examples:

Delete a Group:

DELETE /endpoints/ep1
HTTP/1.1 204 No Content

Delete a Group, verifying its epoch value:

DELETE /endpoints/ep1?epoch=5
HTTP/1.1 204 No Content

Resource Entity 🔗

Resource Metadata vs Resource Document 🔗

The core specification's Resource Metadata vs Resource Document section explains how Resource types might be defined to have a domain-specific document associated with them via their hasdocument model aspect being set to true. For HTTP, clients indicate whether they want to interact with the Resource's xRegistry metadata or the Resource's domain-specific document by the use of a $details suffix on the <RESOURCE>id in its URL. Presence of the $details suffix MUST be interpreted as a request to interact with the xRegistry metadata of the Resource, while its absence MUST be interpreted as a request to interact with the Resource's domain-specific document.

Inappropriate use of $details on an entity that does not support it MUST generate an error (bad_details).

For example:

http://registry.example.com/schemagroups/mygroup/schemas/myschema$details

references the xRegistry metadata of the myschema Resource, while:

http://registry.example.com/schemagroups/mygroup/schemas/myschema

references the (domain-specific) schema document associated with the myschema Resource.

If a Resource type does not support domain-specific documents (i.e. hasdocument is set to false), then use of the $details suffix in a request URL MUST be treated the same as if it were absent and any URLs in server response messages referencing that Resource (e.g. self) MUST NOT include it.

Serializing Resource Domain-Specific Documents 🔗

This section goes into more details concerning situations where a Resource type is defined to support domain-specific documents (i.e. hasdocument is set to true.

When a Resource is serialized as its underlying domain-specific document, in other words $details is not appended to its URL path, the HTTP body of requests and responses MUST be the exact bytes of that document. If the document is empty, then the HTTP body MUST be empty (zero length).

In this serialization mode, it might be useful for clients to also interact with some of the Resource's xRegistry metadata. To support this, some of the Resource's xRegistry metadata MAY appear as HTTP headers in messages.

On responses, unless otherwise stated, all top-level scalar attributes of the Resource SHOULD appear as HTTP headers where the header name is the name of the attribute prefixed with xRegistry-. Note, the optionality of this requirement is not to allow for servers to decide whether or not to do so, rather it is to allow for No-Code Servers servers that might not be able to control the HTTP response headers.

The <RESOURCE> and <RESOURCEbase64> attributes MUST NOT be serialized as HTTP headers, even if their values can be considered "scalar", because their values will appear in the HTTP body.

Top-level map attributes whose values are of scalar types SHOULD also appear as HTTP headers (each key having its own HTTP header) and in those cases the HTTP header names will be of the form: xRegistry-<MAPNAME>.<KEYNAME>. Note that map keys MAY contain the . character, so any . after the <MAPNAME> is part of the key name. See HTTP Header Values for additional information and labels for an example of one such attribute.

Certain attributes do not follow this rule if a standard HTTP header name is defined for that semantic purpose. See the HTTP-Specific Attribute Processing Rules section for more information.

Complex top-level attributes (e.g. arrays, objects, non-scalar maps) MUST NOT appear as HTTP headers.

On update requests, similar serialization rules apply. However, rather than these headers being REQUIRED, the client would only need to include those top-level attributes that they would like to change. But, including unchanged attributes MAY be done. Any attributes not included in request messages MUST be interpreted as a request to leave their values unchanged. Using a value of null (case-sensitive) MUST be processed as a request to delete that attribute.

Any top-level map attributes that appear as HTTP headers MUST be included in their entirety and any missing keys MUST be interpreted as a request to delete those keys from the map.

Since only some types of attributes can appear as HTTP headers, in order to manage the full set of attribute the xRegistry metadata view (via use of the $details URL suffix) MUST be used instead.

When a Resource (not a Version) is serialized with the Resource document in the HTTP body, it MUST adhere to this form:

Content-Type: <STRING> ?
xRegistry-<RESOURCE>id: <STRING>           # ID of Resource, not default Version
xRegistry-versionid: <STRING>              # ID of the default Version
xRegistry-self: <URL>                      # Resource URL, not default Version
xRegistry-xid: <URI>                       # Relative Resource URI
xRegistry-epoch: <UINTEGER>                # Start default Version's attributes
xRegistry-name: <STRING> ?
xRegistry-isdefault: true
xRegistry-description: <STRING> ?
xRegistry-documentation: <URL> ?
xRegistry-icon: <URL> ?
xRegistry-labels.<KEY>: <STRING> *
xRegistry-createdat: <TIMESTAMP>
xRegistry-modifiedat: <TIMESTAMP>
xRegistry-ancestor: <STRING>
xRegistry-<RESOURCE>url: <URL> ?           # End of default Version attributes
xRegistry-metaurl: <URL>                   # Resource-level attributes
xRegistry-versionsurl: <URL>
xRegistry-versionscount: <UINTEGER>
Location: <URL> ?
Content-Location: <URL> ?
Content-Disposition: <STRING> ?

... Resource document excluded for brevity ... ?

Where:

Version serialization will look similar, but without the Resource-level attributes, and MUST be of the form:

Content-Type: <STRING> ?
xRegistry-<RESOURCE>id: <STRING>           # ID of Resource, not default Version
xRegistry-versionid: <STRING>              # ID of the default Version
xRegistry-self: <URL>                      # Version URL
xRegistry-xid: <URI>                       # Relative Version URI
xRegistry-epoch: <UINTEGER>
xRegistry-name: <STRING> ?
xRegistry-isdefault: <BOOLEAN>
xRegistry-description: <STRING> ?
xRegistry-documentation: <URL> ?
xRegistry-icon: <URL> ?
xRegistry-labels.<KEY>: <STRING> *
xRegistry-createdat: <TIMESTAMP>
xRegistry-modifiedat: <TIMESTAMP>
xRegistry-ancestor: <STRING>
xRegistry-<RESOURCE>url: <URL> ?           # End of default Version attributes
Location: <URL> ?
Content-Location: <URL> ?
Content-Disposition: <STRING> ?

... Version document excluded for brevity ... ?

Where:

Scalar default Version extension attributes MUST also appear as xRegistry- HTTP headers.

Notice that for Resources, the meta and versions attributes are not included since they are complex data types.

Note: HTTP header values can be empty strings but some client-side tooling might make it challenging to produce them. For example, curl requires the header to be specified as -Hmyheader; - notice the semicolon(;) is used instead of colon(:). So, this might be something to consider when choosing to use attributes, or labels, that can be empty strings.

GET /<GROUPS>/<GID>/<RESOURCES> 🔗

A server MAY support clients retrieving a Resource collection from a Group via an HTTP GET directed to the owning Group's <RESOURCE> collection URL.

The request MUST be of the form:

GET /<GROUPS>/<GID>/<RESOURCES>

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Link: <URL>;rel=next;count=<UINTEGER> ?

{
  "<KEY>": {                                    # <RESOURCE>id
    ... Resource entity excluded for brevity ...
  } *
}

Examples:

Retrieve all messages of an endpoint whose <GROUP>id is ep1:

GET /endpoints/ep1/messages
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Link: <https://example.com/endpoints/ep1/messages&page=2>;rel=next;count=100

{
  "msg1": {
    "messageid": "msg1",
    "versionid": "1.0",
    "self": "https://example.com/endpoints/ep1/messages/msg1",
    "xid": "/endpoints/ep1/messages/msg1",
    "epoch": 1,
    "name": "Blob Created",
    "isdefault": true,
    "createdat": "2024-04-30T12:00:00Z",
    "modifiedat": "2024-04-30T12:00:01Z",
    "ancestor": "1.0",

    "metaurl": "https://example.com/endpoints/ep1/messages/msg1/meta",
    "versionsurl": "https://example.com/endpoints/ep1/messages/msg1/versions",
    "versionscount": 1
  }
}

PATCH and POST /<GROUPS>/<GID>/<RESOURCES> 🔗

A server MAY support clients creating/updating one or more Resources within a Group via an HTTP PATCH or POST directed to the owning Group's <RESOURCE> collection URL.

The processing of these APIs is defined in the Creating or Updating Entities section - see the discussion of the POST/PATCH <PATH-TO-COLLECTION> variants.

The request MUST be of the form:

PATCH /<GROUPS>/<GID>/<RESOURCES>
Content-Type: application/json; charset=utf-8
or
POST /<GROUPS>/<GID>/<RESOURCES>
Content-Type: application/json; charset=utf-8

{
   "<KEY>": {                                      # <RESOURCE>id
     ... Resource entity excluded for brevity ...
  } *
}

A successful response MUST be of the form:

HTTP/1.1 200 OK
{
   "<KEY>": {                                      # <RESOURCE>id
     ... Resource entity excluded for brevity ...
  } *
}

Examples:

POST /endpoints/ep1/messages
Content-Type: application/json; charset=utf-8

{
  "msg1": {
    "endpointid": "msg1",
    ... remainder of msg1 definition excluded for brevity ...
  },
  "msg2": {
    "endpointid": "msg2",
    ... remainder of msg2 definition excluded for brevity ...
  }
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "msg1": {
    "endpointid": "msg1",
    ... remainder of msg1 definition excluded for brevity ...
  },
  "msg2": {
    "endpointid": "msg2",
    ... remainder of msg2 definition excluded for brevity ...
  }
}

DELETE /<GROUPS>/<GID>/<RESOURCES> 🔗

A server MAY support clients deleting one or more Resources within a Group via an HTTP DELETE directed to the owning Group's <RESOURCE> collection URL.

The processing of this API is defined in the Deleting Entities section of the core specification.

The request MUST be of the form:

DELETE /<GROUPS>/<GID>/<RESOURCES>

{
   "<KEY>": {                            # <RESOURCE>id
     "epoch": <UINTEGER> ?
   } *
} ?

A successful response MUST be of the form:

HTTP/1.1 200 OK
or
HTTP/1.1 204 No Content

Examples:

Delete multiple Resources:

DELETE /endpoints/ep1/messages

{
  "msg1": {
    "epoch": 5
  },
  "msg2": {}
}
HTTP/1.1 204 No Content

Notice that the epoch value for msg1 will be verified prior to the delete, but no such check will happen for msg2.

GET /<GROUPS>/<GID>/<RESOURCES>/<RID> 🔗

A server MAY support clients retrieving a Resource within a Group via an HTTP GET directed to the Resource entity.

The request MUST be of the form:

GET /<GROUPS>/<GID>/<RESOURCES>/<RID>[$details]

Where the $details suffix controls whether the request is directed to the Resource metadata or to the Resource domain-specific document. See Resource Metadata vs Resource Document for more information.

When $details is used, or the Resource type is not configured to have a domain-specific document, then a successful response MUST be:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Location: <URL> ?

{
  ... Resource entity excluded for brevity ...
}

Where:

When $details is not used and the Resource type is configured to have a domain-specific document, then a successful response MUST be either:

For either response, the Resource's default Version attributes, along with the meta and versions related scalar attributes, MUST be serialized as HTTP xRegistry- headers.

A successful response MUST be of the form:

HTTP/1.1 200 OK
or
HTTP/1.1 303 See Other
Content-Type: <STRING> ?
xRegistry-<RESOURCE>id: <STRING>
xRegistry-versionid: <STRING>
xRegistry-self: <URL>
xRegistry-xid: <XID>
xRegistry-epoch: <UINTEGER>
xRegistry-name: <STRING> ?
xRegistry-isdefault: true
xRegistry-description: <STRING> ?
xRegistry-documentation: <URL> ?
xRegistry-icon: <URL> ?
xRegistry-labels.<KEY>: <STRING> *
xRegistry-createdat: <TIMESTAMP>
xRegistry-modifiedat: <TIMESTAMP>
xRegistry-ancestor: <STRING>
xRegistry-<RESOURCE>url: <URL> ?       # If Resource is not in body
xRegistry-metaurl: <URL>
xRegistry-versionsurl: <URL>
xRegistry-versionscount: <UINTEGER>
Location: <URL> ?                      # If 303 is returned
Content-Location: <URL> ?
Content-Disposition: <STRING> ?

... Resource document ...              # If <RESOURCE>url is not set

Where:

Examples:

Retrieve a message Resource as xRegistry metadata:

GET /endpoints/ep1/messages/msg1$details
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Location: https://example.com/endpoints/ep1/messages/msg1/versions/1

{
  "messageid": "msg1",
  "versionid": "1",
  "self": "https://example.com/endpoints/ep1/messages/msg1","
  "xid": "/endpoints/ep1/messages/msg1",
  "epoch": 1,
  "name": "Blob Created",
  "isdefault": true,
  "createdat": "2024-04-30T12:00:00Z",
  "modifiedat": "2024-04-30T12:00:01Z",
  "ancestor": "1",

  "metaurl": "https://example.com/endpoints/ep1/messages/msg1/meta",
  "versionsurl": "https://example.com/endpoints/ep1/messages/msg1/versions",
  "versionscount": 1
}

PATCH and PUT /<GROUPS>/<GID>/<RESOURCES>/<RID> 🔗

A server MAY support clients creating, or updating, a Resource within a Group via an HTTP PATCH or PUT directed to the Resource entity.

The processing of these APIs is defined in the Creating or Updating Entities section.

The $details suffix controls whether the request is directed to the Resource metadata or to the Resource domain-specific document. See Resource Metadata vs Resource Document for more information.

When directed to the Resource metadata, the request MUST be of the form:

PATCH /<GROUPS>/<GID>/<RESOURCES>/<RID>[$details]
Content-Type: application/json; charset=utf-8
or
PUT /<GROUPS>/<GID>/<RESOURCES>/<RID>[$details]
Content-Type: application/json; charset=utf-8

{ ... Resource entity excluded for brevity ... }

The response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ ... Resource entity excluded for brevity ... }

When directed to the Resource's domain-specific document, the request MUST be of the form:

PUT /<GROUPS>/<GID>/<RESOURCES>/<RID>
Content-Type: application/json; charset=utf-8

Content-Type: <STRING> ?
xRegistry-<RESOURCE>id: <STRING> ?
xRegistry-versionid: <STRING> ?         # Version-level attributes
xRegistry-epoch: <UINTEGER> ?
xRegistry-name: <STRING> ?
xRegistry-description: <STRING> ?
xRegistry-documentation: <URL> ?
xRegistry-icon: <URL> ?
xRegistry-labels.<KEY>: <STRING> *
xRegistry-createdat: <TIMESTAMP> ?
xRegistry-modifiedat: <TIMESTAMP> ?
xRegistry-ancestor: <STRING> ?
xRegistry-<RESOURCE>url: <URL> ?

... Resource document excluded for brevity ... ?

Note that PATCH for Resources with domain-specific documents is not supported.

A successful response MUST be of the form:

HTTP/1.1 200 OK
or
HTTP/1.1 201 Created
or
HTTP/1.1 303 See Other
Content-Type: <STRING> ?
xRegistry-<RESOURCE>id: <STRING>
xRegistry-versionid: <STRING>
xRegistry-self: <URL>
xRegistry-xid: <XID>
xRegistry-epoch: <UINTEGER>
xRegistry-name: <STRING> ?
xRegistry-isdefault: true
xRegistry-description: <STRING> ?
xRegistry-documentation: <URL> ?
xRegistry-icon: <URL> ?
xRegistry-labels.<KEY>: <STRING> *
xRegistry-createdat: <TIMESTAMP>
xRegistry-modifiedat: <TIMESTAMP>
xRegistry-ancestor: <STRING>
xRegistry-<RESOURCE>url: <URL> ?       # If Resource is not in body
xRegistry-metaurl: <URL>
xRegistry-versionsurl: <URL>
xRegistry-versionscount: <UINTEGER>
Location: <URL> ?                      # If 201 or 303 is returned
Content-Location: <URL> ?
Content-Disposition: <STRING> ?

... Resource document ...              # If <RESOURCE>url is not set

Where:

Examples:

Create a new Resource:

PUT /endpoints/ep1/messages/msg1
Content-Type: application/json; charset=utf-8
xRegistry-name: Blob Created

{ ... Definition of "Blob Created" event (document) excluded for brevity ... }
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
xRegistry-messageid: msg1
xRegistry-versionid: 1
xRegistry-self: https://example.com/endpoints/ep1/messages/msg1
xRegistry-xid: /endpoints/ep1/messages/msg1
xRegistry-epoch: 1
xRegistry-name: Blob Created
xRegistry-isdefault: true
xRegistry-ancestor: 1
xRegistry-metaurl: https://example.com/endpoints/ep1/messages/msg1/meta
xRegistry-versionsurl: https://example.com/endpoints/ep1/messages/msg1/versions
xRegistry-versionscount: 1
Location: https://example.com/endpoints/ep1/messages/msg1
Content-Location: https://example.com/endpoints/ep1/messages/msg1/versions/1
Content-Disposition: msg1

{ ... Definition of "Blob Created" event (document) excluded for brevity ... }

Update the default Version of a Resource as xRegistry metadata:

PUT /endpoints/ep1/messages/msg1$details
Content-Type: application/json; charset=utf-8

{
  "epoch": 1,
  "name": "Blob Created",
  "description": "a cool event",

  "message": {
    # Updated definition of a "Blob Created" event excluded for brevity
  }
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Location: https://example.com/endpoints/ep1/messages/msg1/versions/1

{
  "messageid": "msg1",
  "versionid": "1",
  "self": "https://example.com/endpoints/ep1/messages/msg1",
  "xid": "/endpoints/ep1/messages/msg1",
  "epoch": 2,
  "name": "Blob Created",
  "isdefault": true,
  "description": "a cool event",
  "createdat": "2024-04-30T12:00:00Z",
  "modifiedat": "2024-04-30T12:00:01Z",
  "ancestor": "1",

  "message": {
    # Updated definition of a "Blob Created" event excluded for brevity
  },

  "metaurl": "https://example.com/endpoints/ep1/messages/msg1/meta",
  "versionsurl": "https://example.com/endpoints/ep1/messages/msg1/versions",
  "versionscount": 1
}

POST /<GROUPS>/<GID>/<RESOURCES>/<RID> 🔗

A server MAY support clients creating, or updating, a single Version of a Resource via an HTTP POST directed to the Resource entity.

The processing of this API is defined in the Creating or Updating Entities section.

The $details suffix controls whether the request is directed to the Version metadata or to the Version domain-specific document. See Resource Metadata vs Resource Document for more information.

When directed to the metadata of the entity, the request MUST be of the form:

POST /<GROUPS>/<GID>/<RESOURCES>/<RID>[$details]
Content-Type: application/json; charset=utf-8

{ ... Version entity excluded for brevity ... }

The response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ ... Version entity excluded for brevity ... }

When directed to the entity's domain-specific document, the request MUST be of the form:

POST /<GROUPS>/<GID>/<RESOURCES>/<RID>
Content-Type: application/json; charset=utf-8

Content-Type: <STRING> ?
xRegistry-<RESOURCE>id: <STRING> ?
xRegistry-versionid: <STRING> ?         # Version-level attributes
xRegistry-epoch: <UINTEGER> ?
xRegistry-name: <STRING> ?
xRegistry-description: <STRING> ?
xRegistry-documentation: <URL> ?
xRegistry-icon: <URL> ?
xRegistry-labels.<KEY>: <STRING> *
xRegistry-createdat: <TIMESTAMP> ?
xRegistry-modifiedat: <TIMESTAMP> ?
xRegistry-ancestor: <STRING> ?
xRegistry-<RESOURCE>url: <URL> ?

... Version document excluded for brevity ... ?

A successful response MUST be of the form:

HTTP/1.1 200 OK
or
HTTP/1.1 201 Created
or
HTTP/1.1 303 See Other
Content-Type: <STRING> ?
xRegistry-<RESOURCE>id: <STRING>
xRegistry-versionid: <STRING>
xRegistry-self: <URL>
xRegistry-xid: <XID>
xRegistry-epoch: <UINTEGER>
xRegistry-name: <STRING> ?
xRegistry-isdefault: <BOOLEAN>
xRegistry-description: <STRING> ?
xRegistry-documentation: <URL> ?
xRegistry-icon: <URL> ?
xRegistry-labels.<KEY>: <STRING> *
xRegistry-createdat: <TIMESTAMP>
xRegistry-modifiedat: <TIMESTAMP>
xRegistry-ancestor: <STRING>
xRegistry-<RESOURCE>url: <URL> ?       # If Resource is not in body
Location: <URL> ?                      # If 201 or 303 is returned
Content-Location: <URL> ?
Content-Disposition: <STRING> ?

... Version document excluded for brevity ...  # If <RESOURCE>url is not set

Where:

Examples:

Create a new Version:

POST /endpoints/ep1/messages/msg1
Content-Type: application/json; charset=utf-8
xRegistry-name: Blob Created

{ ... Definition of "Blob Created" event (document) excluded for brevity ... }
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
xRegistry-messageid: msg1
xRegistry-versionid: 2
xRegistry-self: https://example.com/endpoints/ep1/messages/msg1/versions/2
xRegistry-xid: /endpoints/ep1/messages/msg1/versions/2
xRegistry-epoch: 1
xRegistry-name: Blob Created
xRegistry-isdefault: true
xRegistry-ancestor: 1
Location: https://example.com/endpoints/ep1/messages/msg1/versions/v2
Content-Location: https://example.com/endpoints/ep1/messages/msg1/versions/2
Content-Disposition: msg1

{ ... Definition of "Blob Created" event (document) excluded for brevity ... }

Update a Version of a Resource as xRegistry metadata:

POST /endpoints/ep1/messages/msg1$details
Content-Type: application/json; charset=utf-8

{
  "epoch": 1,
  "name": "Blob Created",
  "description": "a cool event",

  "message": {
    # Updated definition of a "Blob Created" event excluded for brevity
  }
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Location: https://example.com/endpoints/ep1/messages/msg1/versions/1

{
  "messageid": "msg1",
  "versionid": "1",
  "self": "https://example.com/endpoints/ep1/messages/msg1/versions/1",
  "xid": "/endpoints/ep1/messages/msg1",
  "epoch": 2,
  "name": "Blob Created",
  "isdefault": true,
  "description": "a cool event",
  "createdat": "2024-04-30T12:00:00Z",
  "modifiedat": "2024-04-30T12:00:01Z",
  "ancestor": "1",

  "message": {
    # Updated definition of a "Blob Created" event excluded for brevity
  },
}

DELETE /<GROUPS>/<GID>/<RESOURCES>/<RID> 🔗

A server MAY support clients deleting a Resource via an HTTP DELETE directed to the Resource entity.

The processing of this API is defined in the Deleting Entities section of the core specification.

The request MUST be of the form:

DELETE /<GROUPS>/<GID>/<RESOURCES>/<RID>

A successful response MUST be of the form:

HTTP/1.1 200 OK
or
HTTP/1.1 204 No Content

Examples:

Delete a Resource:

DELETE /endpoints/ep1/messages/msg1
HTTP/1.1 204 No Content

Delete a Resource, verifying its epoch value:

DELETE /endpoints/ep1/messages/msg1?epoch=5
HTTP/1.1 204 No Content

Meta Entity 🔗

GET /<GROUPS>/<GID>/<RESOURCES>/<RID>/meta 🔗

A server MAY support clients retrieving a Resource's Meta entity via an HTTP GET directed to the Resource's Meta entity.

The request MUST be of the form:

GET /<GROUPS>/<GID>/<RESOURCES>/<RID>/meta

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ .. Meta entity excluded for brevity ...  }

Examples:

Retrieve a Resource's Meta entity:

GET /endpoints/ep1/messages/msg1/meta
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "messageid": "msg1",
  "self": "https://example.com/endpoints/ep1/messages/msg1/meta",
  "xid": "/endpoints/ep1/messages/msg1/meta",
  "epoch": 2,
  "createdat": "2024-04-30T12:00:00Z",
  "modifiedat": "2024-04-30T12:00:01Z",
  "compatibility": "none",
  "defaultversionid": "v2.0",
  "defaultversionurl": "https://example.com/endpoints/ep1/messages/msg1/versions/v2.0",
  "defaultversionsticky": false
}

PATCH and PUT /<GROUPS>/<GID>/<RESOURCES>/<RID>/meta 🔗

A server MAY support clients updating a Resource's Meta entity via an HTTP PATCH or PUT directed to the Resource's Meta entity.

The processing of these APIs is defined in the Creating or Updating Entities section.

The request MUST be of the form:

PATCH /<GROUPS>/<GID>/<RESOURCES>/<RID>/meta
Content-Type: application/json; charset=utf-8
or
PUT /<GROUPS>/<GID>/<RESOURCES>/<RID>/meta
Content-Type: application/json; charset=utf-8

{ ... Meta entity excluded for brevity ... }

The response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ ... Meta entity excluded for brevity ... }

Examples:

Update a Resource's defaultversionid attribute:

PATCH /endpoints/ep1/messages/msg1/meta
Content-Type: application/json; charset=utf-8

{
  "defaultversionid": "v2.0"
}
HTTP/1.1 200 Created
Content-Type: application/json; charset=utf-8

{
  "messageid": "msg1",
  "self": "https://example.com/endpoints/ep1/messages/msg1/meta",
  "xid": "/endpoints/ep1/messages/msg1/meta",
  "epoch": 2,
  "createdat": "2024-04-30T12:00:00Z",
  "modifiedat": "2024-04-30T12:00:01Z",
  "compatibility": "none",
  "defaultversionid": "v2.0",
  "defaultversionurl": "https://example.com/endpoints/ep1/messages/msg1/versions/v2.0",
  "defaultversionsticky": false
}

DELETE /<GROUPS>/<GID>/<RESOURCES>/<RID>/meta 🔗

A DELETE directed to the Meta entity is not supported and MUST generate an error (action_not_supported).

Version Entity 🔗

GET /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions 🔗

A server MAY support clients retrieving the versions collection of a Resource via an HTTP GET directed to the owning Resource's versions collection URL.

The request MUST be of the form:

GET /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Link: <URL>;rel=next;count=<UINTEGER> ?

{
  "<KEY>": {                                    # The versionid
    ... Version entity excluded for brevity ...
  } *
}

Examples:

Retrieve all Version of a message Resource:

GET /endpoints/ep1/messages/msg1/versions
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Link: <https://example.com/endpoints/ep1/messages/msg1/versions&page=2>;rel=next;count=100

{
  "1.0": {
    "messageid": "msg1",
    "versionid": "1.0",
    "self": "https://example.com/endpoints/ep1/messages/msg1",
    "xid": "/endpoints/ep1/messages/msg1",
    "epoch": 1,
    "name": "Blob Created",
    "isdefault": true,
    "createdat": "2024-04-30T12:00:00Z",
    "modifiedat": "2024-04-30T12:00:01Z",
    "ancestor": "1.0"
  }
}

PATCH and POST /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions 🔗

A server MAY support clients creating/updating one or more Versions, of a Resource via an HTTP PATCH or POST directed to the owning Resource's versions collection URL.

The processing of these APIs is defined in the Creating or Updating Entities section - see the discussion of the POST/PATCH <PATH-TO-COLLECTION> variants.

The request MUST be of the form:

PATCH /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions
Content-Type: application/json; charset=utf-8
or
POST /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions
Content-Type: application/json; charset=utf-8

{
   "<KEY>": {                                      # <GROUP>id
     ... Version entity excluded for brevity ...
  } *
}

The response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
   "<KEY>": {                                      # <GROUP>id
     ... Version entity excluded for brevity ...
  } *
}

Examples:

Update several Versions (adding a label):

PATCH /endpoints/ep1/messages/msg1/versions
Content-Type: application/json; charset=utf-8

{
  "1": {
    "labels": { "customer": "abc" },
  },
  "2": {
    "labels": { "customer": "abc" },
  },
  "3": {
    "labels": { "customer": "abc" },
  }
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "1": {
    "messageid": "msg1",
    "versionid": "1",
    "labels": { "customer": "abc" },
    # Remainder of Version entity excluded for brevity
  },
  "2": {
    "messageid": "msg1",
    "versionid": "2",
    "labels": { "customer": "abc" },
    # Remainder of Version entity excluded for brevity
  },
  "3": {
    "messageid": "msg1",
    "versionid": "3",
    "labels": { "customer": "abc" },
    # Remainder of Version entity excluded for brevity
  }
]

Note that in this case, the new "label" replaces all existing labels, it is not a "merge" operation because all attributes need to be specified in their entirety.

DELETE /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions 🔗

A server MAY support clients deleting one or more Versions within a specified Resource via an HTTP DELETE directed to the owning Resource's versions collection URL.

The processing of this API is defined in the Deleting Entities section of the core specification.

The request MUST be of the form:

DELETE /<GROUPS>/<GID>/<RESOURCES>/versions

{
   "<KEY>": {                            # versionid
     "epoch": <UINTEGER> ?
   } *
} ?

A successful response MUST be of the form:

HTTP/1.1 200 OK
or
HTTP/1.1 204 No Content

Examples:

Delete multiple Versions:

DELETE /endpoints/ep1/messages/msg1/versions

{
  "v1.0": {
    "epoch": 5
  },
  "v2.0": {}
}
HTTP/1.1 204 No Content

Notice that the epoch value for v1.0 will be verified prior to the delete, but no such check will happen for v2.0.

GET /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions/<VID> 🔗

A server MAY support clients retrieving a Version of a Resource via an HTTP GET directed to the Version entity.

The request MUST be of the form:

GET /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions/<VID>[$details]

Where the $details suffix controls whether the request is directed to the Version metadata or to the Version domain-specific document. See Resource Metadata vs Resource Document for more information.

When $details is used, or the Resource is not configured to have a domain-specific document, then a successful response MUST be of the form:

A successful response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  ... Version entity excluded for brevity ...
}

When $details is not used and the Resource is configured to have a domain-specific document, then a successful response MUST either return the Version's domain-specific document, or an HTTP redirect to the <RESOURCE>url value if set.

In the case of returning the Version's domain-specific document, the response MUST be of the form:

HTTP/1.1 200 OK
or
HTTP/1.2 303 See Other
Content-Type: <STRING> ?
xRegistry-<RESOURCE>id: <STRING>
xRegistry-versionid: <STRING>
xRegistry-self: <URL>
xRegistry-xid: <XID>
xRegistry-epoch: <UINTEGER>
xRegistry-name: <STRING> ?
xRegistry-isdefault: <BOOLEAN>
xRegistry-description: <STRING> ?
xRegistry-documentation: <URL> ?
xRegistry-icon: <URL> ?
xRegistry-labels.<KEY>: <STRING> *
xRegistry-createdat: <TIMESTAMP>
xRegistry-modifiedat: <TIMESTAMP>
xRegistry-ancestor: <STRING>
Location: <URL> ?                        # If 303 is returned
Content-Disposition: <STRING> ?

... Version document ...                 # If <RESOURCE>url is not set

Where:

Examples:

Retrieve a specific Version of a schema Resource as xRegistry metadata:

GET /schemagroups/g1/schemas/myschema/versions/1.0$details
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "schemaid": "myschema",
  "versionid": "1.0",
  "self": "https://example.com/schemagroups/g1/schemas/myschema/versions/1.0",
  "xid": "/endpoints/ep1/messages/msg1/versions/1.0",
  "epoch": 2,
  "isdefault": true,
  "createdat": "2024-04-30T12:00:00Z",
  "modifiedat": "2024-04-30T12:00:01Z",
  "ancestor": "1.0"
}

Retrieve the domain-specific document of the same schema Resource:

GET /schemagroups/g1/schemas/myschema/versions/1.0
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
xRegistry-schemaid: myschema
xRegistry-versionid: 1.0
xRegistry-self: https://example.com/schemagroups/g1/schemas/myschema/versions/1.0
xRegistry-xid: /schemagroups/g1/schemas/myschema/versions/1.0
xRegistry-epoch: 2
xRegistry-isdefault: true
xRegistry-createdat: 2024-04-30T12:00:00Z
xRegistry-modifiedat: 2024-04-30T12:00:01Z
xRegistry-ancestor: 1.0
Content-Disposition: myschema

{ ... Contents of a schema doc excluded for brevity ...  }

PATCH and PUT /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions/<VID> 🔗

A server MAY support clients creating or updating a Version of a Resource via an HTTP PATCH or PUT directed to the Version.

The processing of these APIs is defined in the Creating or Updating Entities section.

The $details suffix controls whether the request is directed to the Resource metadata or to the Resource domain-specific document. See Resource Metadata vs Resource Document for more information.

When directed to the Version metadata, the request MUST be of the form:

PATCH /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions/<VID>[$details]
Content-Type: application/json; charset=utf-8
or
PUT /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions/<VID>[$details]
Content-Type: application/json; charset=utf-8

{ ... Version entity excluded for brevity ... }

The response MUST be of the form:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ ... Version entity excluded for brevity ... }

When directed to the Version's domain-specific document, the request MUST be of the form:

PUT /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions/<VID>
Content-Type: application/json; charset=utf-8

Content-Type: <STRING> ?
xRegistry-<RESOURCE>id: <STRING> ?
xRegistry-versionid: <STRING> ?         # Version-level attributes
xRegistry-epoch: <UINTEGER> ?
xRegistry-name: <STRING> ?
xRegistry-isdefault: <BOOLEAN>
xRegistry-description: <STRING> ?
xRegistry-documentation: <URL> ?
xRegistry-icon: <URL> ?
xRegistry-labels.<KEY>: <STRING> *
xRegistry-createdat: <TIMESTAMP> ?
xRegistry-modifiedat: <TIMESTAMP> ?
xRegistry-ancestor: <STRING> ?
xRegistry-<RESOURCE>url: <URL> ?

... Version document excluded for brevity ... ?

Note that PATCH for Resources with domain-specific documents is not supported.

A successful response MUST be of the form:

HTTP/1.1 200 OK
or
HTTP/1.1 201 Created
or
HTTP/1.1 303 See Other
Content-Type: <STRING> ?
xRegistry-<RESOURCE>id: <STRING>
xRegistry-versionid: <STRING>
xRegistry-self: <URL>
xRegistry-xid: <XID>
xRegistry-epoch: <UINTEGER>
xRegistry-name: <STRING> ?
xRegistry-isdefault: <BOOLEAN>
xRegistry-description: <STRING> ?
xRegistry-documentation: <URL> ?
xRegistry-icon: <URL> ?
xRegistry-labels.<KEY>: <STRING> *
xRegistry-createdat: <TIMESTAMP>
xRegistry-modifiedat: <TIMESTAMP>
xRegistry-ancestor: <STRING>
xRegistry-<RESOURCE>url: <URL> ?       # If Resource is not in body
Location: <URL> ?                      # If 201 or 303 is returned
Content-Location: <URL> ?
Content-Disposition: <STRING> ?

... Version document ...               # If <RESOURCE>url is not set

Examples:

Create a new Version:

PUT /endpoints/ep1/messages/msg1/versions/v2.0
Content-Type: application/json; charset=utf-8
xRegistry-name: Blob Created v2

{ ... Definition of "Blob Created" event (document) excluded for brevity ... }
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
xRegistry-messageid: msg1
xRegistry-versionid: v2.0
xRegistry-self: https://example.com/endpoints/ep1/messages/msg1/versions/v2.0
xRegistry-xid: /endpoints/ep1/messages/msg1/versions/v2.0
xRegistry-epoch: 1
xRegistry-name: Blob Created v2
xRegistry-isdefault: true
xRegistry-ancestor: v1.0
Location: https://example.com/endpoints/ep1/messages/msg1/versions/v2.0
Content-Location: https://example.com/endpoints/ep1/messages/msg1/versions/v2.0
Content-Disposition: msg1

{ ... Definition of "Blob Created" event (document) excluded for brevity ... }

Update a Version of a Resource as metadata:

PUT /endpoints/ep1/messages/msg1/versions/v2.0$details/
Content-Type: application/json; charset=utf-8

{
  "name": "Blob Created v2",
  "description": "a cool event",
  "message": {
    # Updated definition of a "Blob Created" event excluded for brevity
  },
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Location: https://example.com/endpoints/ep1/messages/msg1/versions/v2.0

{
  "messageid": "msg1",
  "versionid": "1",
  "self": "https://example.com/endpoints/ep1/messages/msg1/versions/v2.0",
  "xid": "/endpoints/ep1/messages/msg1/versions/v2.0",
  "epoch": 2,
  "name": "Blob Created v2",
  "isdefault": true,
  "description": "a cool event",
  "createdat": "2024-04-30T12:00:00Z",
  "modifiedat": "2024-04-30T12:00:01Z",
  "ancestor": "v1.0",

  "message": {
    # Updated definition of a "Blob Created" event excluded for brevity
  },
}

DELETE /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions/<VID> 🔗

A server MAY support clients deleting a Version of a Resource via an HTTP DELETE directed to the Version entity.

The processing of this API is defined in the Deleting Entities section of the core specification.

The request MUST be of the form:

DELETE /<GROUPS>/<GID>/<RESOURCES>/<RID>/versions/<VID>

A successful response MUST be of the form:

HTTP/1.1 200 OK
or
HTTP/1.1 204 No Content

Examples:

Delete a Version:

DELETE /endpoints/ep1/messages/msg1/versions/1.0
HTTP/1.1 204 No Content

Delete a Resource, verifying its epoch value:

DELETE /endpoints/ep1/messages/msg1/versions?epoch=5
HTTP/1.1 204 No Content

Request Flags / Query Parameters 🔗

The core xRegistry specification defines a set of request flags that MAY be used to control the processing of requests as well as influence how response messages are generated. Each flag is mapped to an HTTP query parameter per the following rules:

There are exceptions to these rules as specified by the following:

?filter Flag 🔗

A server MAY support the ?filter query parameter allowing clients to reduce the response entities to just the ones that match certain criteria.

See Filter Flag for more information.

This query parameter MUST be serialized as:

?filter=<EXPRESSION>[,...]*

Where:

The abstract processing logic would be:

?ignore Flag 🔗

A server MAY support the ?ignore query parameter on any write operation to indicate that certain aspects of the request message MUST be ignored by the server).

See Ignore Flag for more information.

This query parameter MUST be serialized as:

?ignore[=<value>[,...]*]

Where:

?inline Flag 🔗

A server MAY support the ?inline query parameter on any request to indicate which nested collections/objects, or potentially large attributes, are to be included in the response message.

See Inline Flag for more information.

This query parameter MUST be serialized as:

?inline[=<PATH>[,...]*]

Where:

?sort Flag 🔗

A server MAY support the ?sort query parameter on any request directed to a collection of Groups, Resources or Versions.

See Sort Flag for more information.

This query parameter MUST be serialized as:

?sort=<ATTRIBUTE>[=asc|desc]

HTTP Header Values 🔗

Some attributes can contain arbitrary UTF-8 string content, and per RFC7230, section 3, HTTP headers MUST only use printable characters from the US-ASCII character set, and are terminated by a CRLF sequence with OPTIONAL whitespace around the header value.

When encoding an attribute's value as an HTTP header, it MUST be percent-encoded as described below. This is compatible with [RFC3986, section 2.1][rfc3986-section-2-1] but is more specific about what needs encoding. The resulting string SHOULD NOT be further encoded. (Rationale: quoted string escaping is unnecessary when every space and double-quote character is already percent-encoded.)

When decoding an HTTP header into an attribute's value, any HTTP header value MUST first be unescaped with respect to double-quoted strings, as described in RFC7230, section 3.2.6. A single round of percent-decoding MUST then be performed as described below. HTTP headers for attribute values do not support parenthetical comments, so the initial unescaping only needs to handle double-quoted values, including processing backslash escapes within double-quoted values. Header values produced via the percent-encoding described here will never include double-quoted values, but they MUST be supported when receiving events, for compatibility with older versions of this specification which did not require double-quote and space characters to be percent-encoded.

Percent encoding is performed by considering each Unicode character within the attribute's canonical string representation. Any character represented in memory as a [Unicode surrogate pair][surrogate-pair] MUST be treated as a single Unicode character. The following characters MUST be percent-encoded:

Space and double-quote are encoded to avoid requiring any further quoting. Percent is encoded to avoid ambiguity with percent-encoding itself.

Steps to encode a Unicode character:

Percent-encoding SHOULD be performed using upper-case for values A-F, but decoding MUST accept lowercase values.

When performing percent-decoding, values that have been unnecessarily percent-encoded MUST be accepted, but encoded byte sequences which are invalid in UTF-8 MUST generate an error (header_error). For example, "%C0%A0" is an overlong encoding of U+0020, and would be rejected.

Example: a header value of "Euro € 😀" SHOULD be encoded as follows:

Error Processing 🔗

When an error is transmitted back to clients, it SHOULD adhere to the format specified in this section - which references the Problem Details for HTTP APIs specification, and when used, MUST be of the following form:

HTTP/1.1 <CODE>
Content-Type: application/json; charset=utf-8

{
  "type": "<URI>",
  "title": "<STRING>",
  "detail": "<STRING>", ?
  "subject": "<STRING>", ?
  "args": {
    "<STRING>": "<STRING>", *    // arg name  -> arg value
  }, ?
  "instance": "<URL>", ?
  "source": "<STRING>", ?
  ... extension error fields ...
}

See the Error Processing section in the core specification for more information.

The following list of HTTP protocol specific errors are defined:

details_required 🔗

extra_xregistry_header 🔗

header_error 🔗

missing_body 🔗