CloudSubscriptions Discovery API is a vendor-neutral API specification for determining what events are available from a particular service, as well as how to subscribe to those events.
This is a working draft. Breaking changes could be made in the next minor version.
In order for consumers to receive events from services, they need to first subscribe, or ask for, events from those services. To do so, there is often a process necessary that involves steps such as discovering which service is of interest, what events it generates and how to create the subscription for those events.
This specification defines a set of APIs to allow for consumers to perform these queries against a "Discovery Endpoint". A Discovery Endpoint acts as a catalog of Services (event producers), that consumers can query to find the ones of interest. Once found, additional metadata is provided in order to consume and subscribe to events. The goal of this API is to be such that tooling can be built where all possible services and event types aren't known in advance.
The deployment relationship of a Discovery Endpoint to the Services and Event Producers that it advertises is out of scope of this specification. For example, a Discovery Endpoint could choose to be implemented as part of a Service, or Event Producer, or it could be acting as an independent aggregator of this metadata. This implementation detail will be transparent to consumers.
The main use-case to consider from the viewpoint of the event consumer is what services are available, and what event types do they generate?
The CloudEvent source
attribute is a potential cause of high fan-out. For
example, consider a blob storage system where each directory constitutes a
distinct source
attribute value. For this reason, the exact CloudEvents
source
attribute value that might appear in a CloudEvent will not appear in
the Discovery API query result. Instead, a higher level classifier (service
)
will be used to represent the abstract notion of the generic event producer of
those events - in the example case, the blob storage service itself.
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.
Note: some of the terms defined below are taken from the CloudEvents specification, and are marked with a reference to the original definition. Any difference between the definitions is accidental and the CloudEvents version takes precedence.
This specification defines the following terms:
A compliant implementation of this specification that advertises the set of Services, Event Types and other metadata to aid in the creation of an Event Subscription.
A "service" represents the entity which manages one or more event sources and is associated with producers that are responsible for the generation of events.
For example, an Object Store service might have a set of event sources where each event source maps to a bucket.
Source [CE]
The "source" is the context in which the occurrence happened. In a distributed system it might consist of multiple Producers. If a source is not aware of CloudEvents, an external producer creates the CloudEvent on behalf of the source.
Producer [CE]
The "producer" is a specific instance, process or device that creates the data structure describing the CloudEvent.
Intermediary [CE]
An "intermediary" receives a message containing an event for the purpose of forwarding it to the next receiver, which might be another intermediary or a Consumer. A typical task for an intermediary is to route the event to receivers based on the information in the event Context.
Consumer [CE]
A "consumer" receives the event and acts upon it. It uses the context and data to execute some logic, which might lead to the occurrence of new events.
The request for events from a Service.
This section defines the resource model of a Discovery Endpoint.
At the core of the data model is the concept of a Service. The API then exposes multiple ways to query over a list of Services. To help explain the Service resource, the following non-normative pseudo json shows its basic structure:
(*
means zero or more, +
means one or more, ?
means optional)
Service:
{
"id": "[a globally unique UUID]",
"epoch": "[discovery entry epoch value]",
"url": "[unique URL to this service]",
"name": "[unique name for this services]",
"description": "[human string]", ?
"docsurl": "[URL reference for human documentation]", ?
"specversions": [ "[ce-specversion value]" + ],
"subscriptionurl": "[URL to which the Subscribe request will be sent]",
"subscriptionconfig": { ?
"[key]": "[value]", *
},
"authscope": "[string]", ?
"protocols": [ "[string]" + ],
"events": [ ?
{ *
"type": "[ce-type value]",
"description": "[human string]", ?
"datacontenttype": "[ce-datacontenttype value]", ?
"dataschema": "[ce-dataschema URI]", ?
"dataschematype": "[string per RFC 2046]", ?
"dataschemacontent": "[schema]", ?
"extensions": [ ?
{ *
"name": "[CE context attribute name]",
"type": "[CE type string]",
"specurl": "[URL to specification defining the extension]" ?
}
]
}
]
}
An example:
{
"id": "cbdd62e8-c095-11ea-b3de-0242ac130004",
"epoch": 1,
"url": "https://example.com/services/widgetService",
"name": "widgets",
"specversions": ["1.0"],
"subscriptionurl": "https://events.example.com",
"protocols": ["HTTP"],
"events": [
{
"type": "com.example.widget.create"
},
{
"type": "com.example.widget.delete"
}
]
}
Note: the above is just a sample and implementations are free to use any internal model they wish to store the data as long as they are compliant with the wire format/API defined by this specification.
The following sections define the attributes that appear in a Service entity.
-
Type:
String
-
Description: A unique identifier for this Service. This value MUST be globally unique. While other metadata about this Service MAY change, this value MUST NOT so that clients can use this attribute to know whether a Service returned by a query is the same Service returned by a previous query.
Whether a change to a Service would result in changing of the Service's metadata (except
id
) and thus be just an update of an existing Service, or whether the change would result in a brand new Service (with a newid
) is not defined by this specification.For example, if a Service's implementation is upgraded to a new version then whether this would result in a new Service (and
id
) or is an update to the existing Service's metadata, is an implementation choice. Likewise, this specification makes no statement, or guarantees, as to the forwards or backwards compatibility a Service as it changes over time.Note, unlike the
name
attribute which only needs to be unique within the scope of a single Discovery Endpoint, the global uniqueness aspect of this attribute allows for the discovery of the same Service across multiple Discovery Endpoints.See the Primer for more information.
-
Constraints:
- REQUIRED in responses from the Discovery Endpoint.
- MUST be a valid UUID per RFC4122.
-
Examples:
bf5ff5cc-d059-4c79-a89a-2513e45a1340
-
Type:
Integer
-
Description: The Discovery Endpoint's epoch value for this Service Entry. This specification does not mandate any particular semantic meaning to the value used. For example, implementations are free to use a value that represents a timestamp or could choose to simply use a monotomically increasing number. The only requirement is that the value MUST always increase each time the Service Entry is updated. This allows for a quick integer comparision to determine which version of this Service Entry is the latest - meaning, the one with the larger integer value.
-
Constraints:
- REQUIRED in responses from the Discovery Endpoint.
-
Examples:
42
915148800
- Type:
String
- Description: A unique human readable identifier for this Service. This value
MUST be unique (case insensitive) within the scope of this Discovery Endpoint.
Note, this differs from the
id
attribute which is globally unique. - Constraints:
- REQUIRED
- Examples:
my storage service
cool git offering
- Type:
URL
- Description: An absolute URL that references this Service. This value MUST be usable in subsequent requests, by authorized clients, to retrieve this Service entity.
- Constraints:
- REQUIRED
- MUST be a non-empty URL
- MUST end with
fsegments
(per RFC1738) of:/services/{id}
whereid
is the Service'sid
attribute.
- Examples:
http://example.com/services/bf5ff5cc-d059-4c79-a89a-2513e45a1340
http://discovery.github.com/services/892abefc-0293-9273-bead-92830efaefa0
- Type:
String
- Description: Human readable description.
- Constraints:
- OPTIONAL
- If present, MUST be a non-empty string
- Type:
URL
- Description: Absolute URL that provides a link to additional documentation about the service. This is intended for a developer to use in order to learn more about this service's events produced.
- Constraints:
- OPTIONAL
- If present, MUST be a non-empty absolute URI
- Examples:
http://cloud.example.com/docs/blobstorage
- Type: Array of
Strings
per RFC 2046 - Description: CloudEvents
specversions
that can be used for events published for this service. - Constraints:
- REQUIRED
- MUST be a non-empty array or non-empty strings
- Type:
URL
- Description: An absolute URL indicating where CloudSubscriptions
subscribe
API calls MUST be sent to. - Constraints:
- REQUIRED
- Type:
Map
ofString
toString
- Description: A map indicating supported options for the
config
parameter for the CloudSubscriptions subscribe() API call. Keys are the name of keys in the allowed config map, the values indicate the type of that parameter, confirming to the CloudEvents type system. TODO: Needs resolution with CloudSubscriptions API - Constraints:
- OPTIONAL
- Examples:
- ??
- Type:
String
- Description: Authorization scope needed for creating subscriptions. The actual meaning of this field is determined on a per-service basis.
- Constraints:
- OPTIONAL
- Example:
storage.read
- Type:
List
ofString
- Description: This field describes the different values that might be passed in
the
protocol
field of the CloudSubscriptions API. The protocols with existing CloudEvents bindings are identified as AMQP, MQTT3, MQTT5, HTTP, KAFKA, and NATS. An implementation MAY add support for further protocols. All services MUST support at least one delivery protocol, and MAY support additional protocols. - Constraints:
- REQUIRED
- MUST be non-empty.
- Examples:
[ "HTTP" ]
[ "HTTP", "AMQP", "KAFKA" ]
- Type:
String
- Description: CloudEvents
type
attribute. - Constraints:
- REQUIRED
- MUST be a non-empty string, following the constraints as defined in the CloudEvents spec.
- Examples:
com.github.pull.create
com.example.object.delete.v2
- Type:
String
- Description: Human readable description.
- Constraints:
- OPTIONAL
- If present, MUST be a non-empty string
- Type:
String
- Description: CloudEvents
datacontenttype
attribute. Indicating how thedata
attribute of subscribed events will be encoded. - Constraints:
- OPTIONAL
- If present, MUST adhere to the format specified in RFC 2046
- Type:
URI
- Description: CloudEvents
datacontenttype
attribute. This identifies the canonical storage location of the schema of thedata
attribute of subscribed events. - Constraints:
- OPTIONAL
- If present, MUST be a non-empty URI
- Type:
String
per RFC 2046 - Description: If using
dataschemacontent
for inline schema storage, thedataschematype
indicates the type of schema represented there. - Constraints:
- OPTIONAL
- If present, MUST adhere to the format specified in RFC 2046
- Examples:
application/json
- Type:
String
- Description: An inline representation of the schema of the
data
attribute encoding mechanism. This is an alternative to using thedataschema
attribute. - Constraints:
- OPTIONAL
- If present, MUST be a non-empty string containing a schema compatible with
the
datacontenttype
. - If
dataschama
is present, this field MUST NOT be present.
- Type:
URI Template
- Description: A URI Template according to RFC 6570 that defines how the source attribute will be generated.
- Constraints:
- OPTIONAL
- If present, MUST be a Level 1 template compliant to RFC 6570
- Examples:
- Type:
Array
of structures - Description: An array or CloudEvents
Extension Context Attributes
that are used for this event
type
. The structure contains the following attributes:name
- the CloudEvents context attribute name used by this extension. It MUST adhere to the CloudEvents context attribute naming rulestype
- the data type of the extension attribute. It MUST adhere to the CloudEvents type systemspecurl
- an attribute pointing to the specification that defines the extension
- Constraints:
- OPTIONAL
- if present, the
name
attribute in the structure is REQUIRED - if present, the
type
attribute in the structure is REQUIRED - if present, the
specurl
attribute in the structure is OPTIONAL
- Examples:
{ "name": "dataref", "type": "URI-reference", "specurl": "https://github.com/cloudevents/spec/blob/master/extensions/dataref.md" }
{
"id": "3db60532-e839-417e-8644-e255f338776a",
"epoch": 1,
"url": "https://storage.example.com/service/storage",
"name": "storage",
"description": "Blob storage in the cloud",
"protocols": ["HTTP"],
"subscriptionurl": "https://cloud.example.com/docs/storage",
"events": [
{
"type": "com.example.storage.object.create",
"specversions": ["1.x-wip"],
"datacontenttype": "application/json",
"dataschema": "http://schemas.example.com/download/com.example.storage.object.create.json",
"sourcetemplate": "https://storage.example.com/service/storage/{objectID}"
}
]
}
The endpoints defined by this specification are broken into two categories:
- Discovery APIs - used to find Services
- Management APIs - used to manage the Services within a Discovery Endpoint
The relative paths specified below are NOT REQUIRED to be at the root of
the fpath
(per RFC1738). However, they are REQUIRED to match the end of it.
For example, the follow are valid URLs/paths:
https://example.com/services
https://example.com/myAggregator/services
If a Discovery Endpoint can perform authorization checks to determine
which client can see which Service, and the requesting client is not allowed
access to a particular Service, then the Discovery Endpoint MUST respond
as if that Service does not exist. For example, it would be excluded from
any array of Services returned and it would result in a 404 Not Found
error for a request to that Service directly.
Unless there is some out-of-band agreement, all APIs MUST use JSON encoding,
which means when there is an HTTP Body the HTTP Content-Type
Header MUST
be application/json
.
All of the API endpoints specified in this section MUST be supported by compliant Discovery Endpoint implementations.
This MUST return an array of zero or more Services. The array MUST contain all Services available via this Discovery Enpoint.
In the case of 200 OK
, the response format MUST adhere to the following:
200 OK
Content-Type: application/json
[
{
"id": "{id}",
"epoch": {int},
"url": "{url}",
"name": "{name}",
... remainder of Service attributes ...
}
...
]
Implementations MAY use the pagination specification if the number of Services returned is large. Clients SHOULD be prepared to support paginated responses.
If this refers to a valid Service, then this MUST return that single Service entity.
The following responses are defined by this specification:
200 OK
and the Service representation in the HTTP Response Body.404 Not Found
if there is no Service with the specifiedid
.
Other responses are allowed, but not defined by this specification.
In the case of 200 OK
, the response format MUST adhere to the following:
200 OK
Content-Type: application/json
{
"id": "{id}",
"epoch": {int},
"url": "{url}",
"name": "{name}",
... remainder of Service attributes ...
}
This returns a single Service whose name
attribute exactly matches the
name
query parameter value specified (case insensitive).
The following responses are defined by this specification:
200 OK
and the Service representation in the HTTP Response Body.404 Not Found
if there is no Service with the specifiedid
.
In the case of 200 OK
, the response format MUST adhere to the following:
200 OK
Content-Type: application/json
{
"id": "{id}",
"epoch": {int},
"url": "{url}",
"name": "{name}",
... remainder of Service attributes ...
}
All of the API endpoints specified in this section MUST be supported by compliant Discovery Endpoint implementations that support being managed.
For any of the following API endpoints, if the Discovery Endpoint chooses to process the incoming request asynchronous then the following rules apply:
- A
202 Accepted
MUST be returned to the request. This indicates that the request has been accepted but not processed yet. - The
202 Accepted
response MUST include aLocation
HTTP Header that points to a "status endpoint", which can be used to determine the status of the original request. The HTTP Response body MAY be empty. - The
202 Accepted
response MAY include aRetry-After
HTTP Header indicating the time, in seconds, that the sender SHOULD wait before querying the status endpoint.
A GET
MAY be sent to the status endpoint to determine the status of the
original request. The following responses are defined:
200 OK
indicates that the original request was successfully processed.- Unless otherwise noted for a specific operation, the response MUST also include the HTTP Headers and HTTP Response Body that is defined for the original operation as if the response were sent synchronously.
202 Accepted
indicates that the original request is still being processed. The response body MAY be empty.406 Not Acceptable
to indicate that the original request failed to be processed correctly. The HTTP response Body SHOULD include additional information as to why it failed.
Other responses are allowed, but not defined by this specification, however
they MUST be related to the GET
itself and not the original request.
How long a Discovery Endpoint supports requests to the status endpoint
is an implementation choice, however, it MUST be available immediately
upon return of the 202 Accepted
from the original request.
This MUST add the specified Services to the list of Services available at this
Discovery Endpoint. The Body of the request message MUST contain an array of
zero or more Service Entries. For convinience to clients, each Service in the
array MAY include the id
or epoch
attributes but they MUST be ignored by
the Discovery Endpoint. Both of these attributes' values MUST be defined by
the Discovery Endpoint.
If any Service specified in the request matches the name
of any existing
Service, or the same name
is used more than once within the request, then
an error MUST be generated.
If the Discovery Endpoint is unable to successully add all of the Services in the incoming request then an error MUST be generated and none of the specified Services are to be added to the Discovery Endpoint.
The follow responses are defined by this specification:
201 Created
if all the specified Services were processed successfully.- If there was only one Service in the incoming request, then the response
MUST include an HTTP
Location
Header with a value that points to the correspdonding Service. - If the request contained more than one Service, then the HTTP
Location
Header MUST NOT appear in the response. - The HTTP Response Body MUST include an array of
id
values whose order and values MUST match the list of Services in the request.
- If there was only one Service in the incoming request, then the response
MUST include an HTTP
Other responses are allowed, but not defined by this specification.
The format of the HTTP Request MUST adhere to the following:
Content-Type: application/json
[
{
"url": "{url}",
"name": "{name}",
... remainder of Service attributes ...
}
...
]
The format of the HTTP Response MUST adhere to the following:
Content-Type: application/json
[
"id": "{id}"
...
]
This MUST add, or update, the specified Services to the list of Services
available at this Discovery Endpoint. The Body of the request message MUST
contain an array of zero or more Service Entries. For convinience to clients,
the presence of the id
and epoch
attributes are OPTIONAL. If id
is
present then it MUST be retained as a result of this operation and any existing
Service with that id
MUST be replaced. If epoch
is present then the
epoch
value of the resulting Service MUST be larger than the maximum of
the incoming Service and any existing Service with that same id
. If either
attribute is not present then the Discovery Endpoint MUST assign appropriate
value to the missing attribute.
If the Discovery Endpoint is unable to successully add all of the Services in the incoming request then an error MUST be generated and none of the specified Services are to be added, or updated, in the Discovery Endpoint.
The Services in the request message MUST be processed in the order in which
they appear. While any error in the overall process MUST rollback any changes
made due to the request, the processing of each Service in the request MUST be
applied as if all previous Services in the request were already completed.
This means that attribute uniqueness checking, such as on the name
attribute, MUST be done on the new state of all Services as if all previously
specified Services in the incoming request were already successfully processed.
For example, if a Discovery Endpoint has a Service called MyService
, it is
possible to rename that Service to YourService
and then to add, or update,
another Service to use MyService
as its name
. But this is only true if
the rename of the first Service happens first the request message.
Likewise, while it might be less than optimal, it is technically possible for
a request to update a Service multiple times if the same id
is used more
than once within a request.
The follow responses are defined by this specification:
201 Created
if all the specified Services were processed successfully.- If there was only one Service in the incoming request, then the response
MUST include an HTTP
Location
Header with a value that points to the correspoding Service. - If the request contained more than one Service, then the HTTP
Location
Header MUST NOT appear in the response. - The HTTP Response Body MUST include an array of
id
values whose order and values MUST match the list of Services in the request.
- If there was only one Service in the incoming request, then the response
MUST include an HTTP
Other responses are allowed, but not defined by this specification.
The format of the HTTP Request MUST adhere to the following:
Content-Type: application/json
[
{
"url": "{url}",
"name": "{name}",
... remainder of Service attributes ...
}
...
]
The format of the HTTP Response MUST adhere to the following:
Content-Type: application/json
[
"id": "{id}"
...
]
This MUST update an existing Service in a Discovery Endpoint. The Body of the
request message MUST contain a single Service definition. The Service MUST
contain an id
attribute that matches the {id}
in the PUT
URL.
The request MAY include the epoch
attribute. If present then the Discovery
Endpoint MUST ensure that the value on the incoming request matches the
current value on the Service. If they do not match then an error MUST be
generated and the Service MUST NOT be updated. However, if the incoming
request does not include this attribute then this verification MUST NOT
be done.
Additionally, if the incoming request did contain the epoch
attribute, then
its value MUST be updated by the Discovery Endpint to a larger value,
indicating that the Service has been updated.
The follow responses are defined by this specification:
200 OK
if Service was updated. The HTTP Response Body MUST include the JSON represenation of the updated Service.404 Not Found
if there is no Service with the specifiedid
.
Other responses are allowed, but not defined by this specification.
The format of the HTTP Request MUST adhere to the following:
Content-Type: application/json
{
"url": "{url}",
"epoch": "{id}",
"name": "{name}",
... remainder of Service attributes ...
}
The format of the HTTP Response MUST adhere to the following:
Content-Type: application/json
{
"url": "{url}",
"epoch": "{id}",
"name": "{name}",
... remainder of Service attributes ...
}
This MUST create or update a Service in a Discovery Endpoint. The Body of the
request message MUST contain a single Service definition, however the presence
of the epoch
attribute is OPTIONAL. The Service MUST contain an id
attribute that matches the {id}
in the PUT
URL.
If epoch
attribute is present then the resulting value of this attribute
MUST result in a value that is larger than both the incoming epoch
value and
any existing Service's epoch
value. If it is not present then the Discovery
Endpoint MUST assign a value that is larger than any existing Service's
epoch
value.
The follow responses are defined by this specification:
200 OK
if an existing Service was updated. The HTTP Response Body MUST include the JSON represenation of the updated Service.201 Created
if a new Service was added. The HTTP Response Body MUST include the JSON represenation of the newly created Service.
Other responses are allowed, but not defined by this specification.
The format of the HTTP Request MUST adhere to the following:
Content-Type: application/json
{
"url": "{url}",
"name": "{name}",
... remainder of Service attributes ...
}
The format of the HTTP Response MUST adhere to the following:
Content-Type: application/json
{
"url": "{url}",
"epoch": "{int}",
"name": "{name}",
... remainder of Service attributes ...
}
This MUST delete the Service at the referenced URL.
The follow responses are defined by this specification:
200 OK
if the new Service was deleted.404 Not Found
if there is no Service with the specifiedid
.
Other responses are allowed, but not defined by this specification.
If the Service is successfully deleted any HTTP GET
to the Service's
original URL MUST return an HTTP 404 Not Found
unless that URL happens to be
reused in the future (e.g. the Service was restored from a backup).
...
The CloudDiscovery API does not place restrictions on implementation's choice of an authentication and authorization mechanism. While the list of entities returned from each query MAY differ, the format of the output MUST adhere to this specification.