diff --git a/CHANGELOG.md b/CHANGELOG.md index 291e4d76..8e8fc7f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,18 @@ For a roadmap including expected timeline, please refer to [ROADMAP.md](./ROADMA ## [unreleased] +### Added + +- Added **Push Transport** mode documentation and schema support + - Push transport allows ORD providers to push ORD documents directly to aggregators via HTTP POST + - Introduced `definitions` property on ORD Document for embedding resource definitions inline + - The key is the URL path (matching `resourceDefinitions[].url`), the value is the raw content as a string + - Content is treated as an opaque text blob, preserving original formatting for all formats (OpenAPI, AsyncAPI, WSDL, etc.) + - Added `embedded` access strategy type for resource definitions that are inline rather than fetched + - Added [embedded access strategy documentation](docs/spec-extensions/access-strategies/embedded.md) + - Added [push transport example document](examples/documents/document-push-transport.json) + - Added draft proposal for [Aggregator Configuration](docs/spec-v1/concepts/aggregator-configuration.md) including validation results endpoint concept + ## [1.14.0] ### Added diff --git a/docs/spec-extensions/access-strategies/embedded.md b/docs/spec-extensions/access-strategies/embedded.md new file mode 100644 index 00000000..ad116df0 --- /dev/null +++ b/docs/spec-extensions/access-strategies/embedded.md @@ -0,0 +1,95 @@ +--- +title: Embedded Access Strategy +description: Resource definition is embedded inline in the ORD document (push transport). +sidebar_position: 1 +--- + +# Embedded Access Strategy + +> **Status**: Draft Proposal (WIP) +> +> This access strategy is part of the [Push Transport](../../spec-v1/index.md#push-transport) proposal. + +## Description + +The `embedded` access strategy indicates that the resource definition content is provided inline within the ORD document itself, rather than being fetched from an external URL. + +This is specifically designed for [push transport](../../spec-v1/index.md#push-transport) scenarios where: + +- The ORD provider pushes the complete ORD document including all resource definitions to an aggregator +- The aggregator does not need to make additional requests to fetch resource definitions +- All metadata is self-contained in a single push request + +The `accessStrategy`.`type` value for it is: `embedded`. + +## How It Works + +When a `resourceDefinition` uses the `embedded` access strategy: + +1. The `url` field still contains the logical path/identifier for the resource definition +2. The actual content is provided in the document-level `definitions` property +3. The `url` value is used as the key to look up the content in `definitions` + +### Example + +```json +{ + "openResourceDiscovery": "1.15", + "apiResources": [ + { + "ordId": "sap.foo:apiResource:myApi:v1", + "resourceDefinitions": [ + { + "type": "openapi-v3", + "mediaType": "application/json", + "url": "/api/my-api/openapi.json", + "accessStrategies": [ + { + "type": "embedded" + } + ] + } + ] + } + ], + "definitions": { + "/api/my-api/openapi.json": "{\"openapi\":\"3.0.0\",\"info\":{\"title\":\"My API\",\"version\":\"1.0.0\"},\"paths\":{}}" + } +} +``` + +## Provider Implementation + +The ORD provider MUST: + +- Set `accessStrategies[].type` to `embedded` for any resource definition whose content is included inline +- Include the resource definition content in the top-level `definitions` property +- Use the same URL path as the key in `definitions` that is referenced in `resourceDefinitions[].url` +- Encode the content as a string (preserving original formatting) + +## Aggregator / Consumer Implementation + +The ORD aggregator or consumer MUST: + +- Recognize `embedded` as an access strategy type +- Look up the content in the `definitions` property using the `url` as the key +- NOT attempt to fetch the URL externally when `embedded` is specified +- Parse the string content according to the `mediaType` specified + +## When to Use + +Use the `embedded` access strategy when: + +- Pushing ORD documents to an aggregator (push transport) +- Integrating ORD publishing into CI/CD pipelines +- The provider cannot or does not want to host resource definitions at accessible URLs +- You want to ensure atomic updates of metadata and definitions together + +## Comparison with `open` + +| Aspect | `open` | `embedded` | +|--------|--------|------------| +| Content location | External URL | Inline in document | +| Fetch required | Yes | No | +| Transport mode | Pull | Push | +| Self-contained | No | Yes | diff --git a/docs/spec-v1/index.md b/docs/spec-v1/index.md index 737d3f29..4ff6d59a 100644 --- a/docs/spec-v1/index.md +++ b/docs/spec-v1/index.md @@ -193,18 +193,192 @@ Manual import of the [ORD document](#ord-document) as a JSON file into an intere - The ORD document alone is sufficient for this type of consumption - All URLs in the document MUST be resolvable (e.g. through `baseUrl` or full URLs) -#### Push Transport +### Push Transport + +In push transport mode, [ORD information](#ord-information) is pushed directly to an [ORD aggregator](#ord-aggregator) via HTTP POST requests. +This mode eliminates the need for an [ORD Provider](#ord-provider) to implement the [ORD Provider API](#ord-provider-api) with its configuration and document endpoints. + +Push transport is particularly suitable for: + +- Static metadata that is known at design-time or deploy-time +- CI/CD pipeline integration where metadata is pushed as part of the build/deployment process +- Providers that cannot or prefer not to host a runtime ORD Provider API + +##### Push Transport - Pros + +- No need to implement and host an ORD Provider API (simpler provider implementation) +- Can be integrated into CI/CD pipelines (design-time or deploy-time) +- Configuration or extensibility changes are pushed immediately when they occur (no polling delay) +- Direct feedback channel for validation errors from the aggregator: validation issues can be returned as part of the push response, making it easier for providers to detect and fix problems immediately (compared to pull where issues may go unnoticed) +- More efficient for tenant-specific (system-instance-aware) metadata: the provider knows exactly when changes occur and can push updates selectively, avoiding the need for aggregators to poll all tenants repeatedly + +##### Push Transport - Cons + +- Every provider needs to know where to push (aggregator endpoint must be known) +- Provider must actively push updates (compared to passive pull) +- Additional authentication/authorization setup between provider and aggregator +- Centralized approach (aggregator must be available to receive pushes) + +##### Push Transport Implementation + +###### ORD Push Document + +For push transport, the standard [ORD document](#ord-document) format is used with one addition: a `definitions` property that allows inline [resource definitions](#resource-definition). + +When using pull transport, resource definitions are referenced via URLs and fetched separately by the aggregator. +In push transport, these definitions can be provided inline within the ORD document itself using the `definitions` property. + +When embedding definitions, the resource definition's access strategy SHOULD be set to [`embedded`](../spec-extensions/access-strategies/embedded.md) to explicitly indicate that the content is inline rather than fetched from a URL. + +The `definitions` property is a dictionary where: +- The **key** is the URL path (as referenced by resources via `resourceDefinitions[].url`) +- The **value** is the raw content of the resource definition as a **string** + +The content is treated as an opaque text blob, preserving original formatting and whitespace. +This works uniformly for all definition formats (OpenAPI JSON/YAML, AsyncAPI, WSDL, JSON Schema, etc.). + +This enables the aggregator to correlate inline definitions with the resources that reference them, keeping all metadata self-contained in a single push request. + +Example structure: +```json +{ + "openResourceDiscovery": "1.14", + "describedSystemInstance": { + "baseUrl": "https://example.com" + }, + "apiResources": [ + { + "ordId": "sap.example:apiResource:my-api:v1", + "resourceDefinitions": [ + { + "type": "openapi-v3", + "url": "/api/my-api/openapi.json", + "mediaType": "application/json", + "accessStrategies": [ + { "type": "embedded" } + ] + } + ] + } + ], + "definitions": { + "/api/my-api/openapi.json": "{\"openapi\":\"3.0.0\",\"info\":{\"title\":\"My API\",\"version\":\"1.0.0\"}}" + } +} +``` -> 🚧 The specification currently does not cover this mode. +###### ORD Aggregator Push API + +An [ORD aggregator](#ord-aggregator) that supports push transport MUST provide a dedicated push API endpoint for receiving ORD documents. + + + +###### Push API Contract + +The push API endpoint MUST: +- Accept HTTP `POST` requests with `Content-Type: application/json` +- Expect the request body to be a valid [ORD document](#ord-document) +- Support the `definitions` property for inline resource definitions +- Return appropriate HTTP status codes: + - `200 OK` or `201 Created` on success + - `400 Bad Request` for any client error (malformed JSON, invalid ORD document, validation failures). Details SHOULD be provided in the response body. + - `401 Unauthorized` or `403 Forbidden` for authentication/authorization failures + - **TODO**: The exact response format for validation errors is not yet formally specified, it's up to the aggregator to define it. + +Example request: +```http +POST /ord/v1/push HTTP/1.1 +Host: aggregator.example.com +Content-Type: application/json +Authorization: Bearer + +{ + "openResourceDiscovery": "1.14", + "describedSystemInstance": { ... }, + "apiResources": [ ... ], + "definitions": { ... } +} +``` + +###### Validation Results Endpoint (Draft) + +> **Status**: Draft Proposal - See [Aggregator Configuration (Draft)](./concepts/aggregator-configuration.md) for details. + +Some validations can only be performed after the aggregator has processed multiple documents (e.g., cross-document reference checks, namespace consistency). +To support deferred validation feedback, aggregators MAY provide a validation results endpoint where providers can retrieve errors, warnings, and info messages. + +This enables: +- Async validation that doesn't block the push request +- Aggregated feedback across multiple pushed documents +- Scoped queries by namespace or package + +###### Provider Authorization + +The aggregator MUST ensure that providers can only push content they are authorized to manage. +Authorization rules depend on the aggregator implementation but typically include: +- Validating that the provider is allowed to describe the claimed [system instance](#system-instance), e.g. by verifying ownership of the `baseUrl` and/or other identifiers in the ORD document +- Validating that the provider owns the [namespaces](#namespace) used in the pushed ORD IDs +- Validating that the push credentials match the expected provider identity + +###### Push Transport Sequence Diagram + +```mermaid +sequenceDiagram + participant Provider as ORD Provider + participant CI as CI/CD Pipeline + participant Aggregator as ORD Aggregator + + Provider->>CI: Trigger build/deployment + CI->>CI: Generate ORD document with inline definitions + CI->>Aggregator: POST ORD document (using access strategy) + Aggregator->>Aggregator: Validate document and authorization + Aggregator-->>CI: Response (success/errors) + + opt On validation errors + CI->>CI: Handle errors, notify developers + end +``` -The Document can be pushed to the interested ORD aggregator, e.g. via a webhook, a known HTTP POST endpoint, or via file upload. +#### Other Modes of Transport -- Every system instance needs to know where the ORD documents need to be pushed to. -- An ORD aggregator might provide a dedicated HTTP POST endpoint for this. -- Changes can be pushed faster and more efficiently compared to the [pull transport](#pull-transport). -- The specification currently does not cover this mode. +Other modes of transport have not yet been standardized/specified. +They are only listed here to outline potential modes that we anticipate. + +##### Import Transport + +Manual import of the [ORD document](#ord-document) as a JSON file into an interested system or tool (offline mode): + +- The system instances do not need to know each other or be integrated in any way +- The ORD document alone is sufficient for this type of consumption, it should include all necessary information and definitions inline (via the `definitions` property as described in the push transport section) -#### Event-Driven Transport +##### Event-Driven Transport > 🚧 The specification currently does not cover this mode. diff --git a/examples/documents/document-push-transport.json b/examples/documents/document-push-transport.json new file mode 100644 index 00000000..e49add1c --- /dev/null +++ b/examples/documents/document-push-transport.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://open-resource-discovery.org/spec-v1/interfaces/Document.schema.json", + "openResourceDiscovery": "1.14", + "description": "Minimal example for push transport with inline resource definition", + "describedSystemInstance": { + "baseUrl": "https://example.com" + }, + "packages": [ + { + "ordId": "sap.example:package:push-demo:v1", + "title": "Push Transport Demo", + "shortDescription": "Demonstrates push transport with inline definitions", + "description": "This package demonstrates push transport with inline resource definitions.", + "version": "1.0.0", + "vendor": "sap:vendor:SAP:" + } + ], + "apiResources": [ + { + "ordId": "sap.example:apiResource:hello-api:v1", + "title": "Hello API", + "shortDescription": "Simple greeting API", + "description": "A simple greeting API that demonstrates push transport.", + "version": "1.0.0", + "visibility": "public", + "releaseStatus": "active", + "partOfPackage": "sap.example:package:push-demo:v1", + "apiProtocol": "rest", + "resourceDefinitions": [ + { + "type": "openapi-v3", + "mediaType": "application/json", + "url": "/api/hello/openapi.json", + "accessStrategies": [ + { + "type": "embedded" + } + ] + } + ], + "entryPoints": ["/api/hello"] + } + ], + "definitions": { + "/api/hello/openapi.json": "{\"openapi\":\"3.0.3\",\"info\":{\"title\":\"Hello API\",\"version\":\"1.0.0\"},\"paths\":{\"/hello\":{\"get\":{\"summary\":\"Get greeting\",\"responses\":{\"200\":{\"description\":\"A greeting message\",\"content\":{\"application/json\":{\"schema\":{\"type\":\"object\",\"properties\":{\"message\":{\"type\":\"string\"}}}}}}}}}}}" + } +} diff --git a/spec/v1/Document.schema.yaml b/spec/v1/Document.schema.yaml index 275eafdc..13810e88 100644 --- a/spec/v1/Document.schema.yaml +++ b/spec/v1/Document.schema.yaml @@ -310,6 +310,10 @@ properties: A tombstone entry MAY be removed after a grace period of 31 days. items: $ref: "#/definitions/Tombstone" + + definitions: + $ref: "#/definitions/InlineDefinitions" + additionalProperties: false required: - openResourceDiscovery @@ -4042,6 +4046,14 @@ definitions: description: |- The resource definitions are openly accessible and not protected via authentication or authorization. Please find a more detailed documentation [here](../../spec-extensions/access-strategies/open). + - const: embedded + description: |- + The resource definition content is provided inline within the ORD document's `definitions` property. + This is used for [push transport](../index.md#push-transport) where definitions are embedded rather than fetched. + The `url` field serves as the key to look up the content in the document's `definitions` dictionary. + Please find a more detailed documentation [here](../../spec-extensions/access-strategies/embedded). + x-introduced-in-version: "1.15.0" + x-feature-status: beta - const: basic-auth description: |- The resource definitions are protected via generic basic auth. @@ -5032,3 +5044,33 @@ definitions: - releaseStatus - partOfPackage additionalProperties: true + + InlineDefinitions: + type: object + title: Inline Definitions + x-introduced-in-version: "1.15.0" + x-feature-status: beta + x-ums-type: ignore + description: |- + A dictionary of inline [resource definitions](../index.md#resource-definition) for [push transport](../index.md#push-transport). + + When using push transport, resource definitions can be provided inline within the ORD document + instead of being referenced via URLs and fetched separately. + + The **key** MUST be the URL path as referenced by resources via `resourceDefinitions[].url`. + The **value** MUST be a string containing the raw content of the resource definition. + + The content is treated as an opaque text blob, preserving original formatting and whitespace. + This works uniformly for all definition formats (OpenAPI JSON/YAML, AsyncAPI, WSDL, JSON Schema, etc.). + + This enables the aggregator to correlate inline definitions with the resources that reference them, + keeping all metadata self-contained in a single push request. + + For pull transport, this property is typically not used as the aggregator fetches definitions via URLs. + additionalProperties: + type: string + examples: + - { + "/api/my-api/openapi.json": "{\"openapi\":\"3.0.0\",\"info\":{\"title\":\"My API\",\"version\":\"1.0.0\"},\"paths\":{}}", + "/api/my-api/schema.wsdl": "\n\n" + } diff --git a/src/generated/spec/v1/types/Document.ts b/src/generated/spec/v1/types/Document.ts index 74746c6f..bf51bd28 100644 --- a/src/generated/spec/v1/types/Document.ts +++ b/src/generated/spec/v1/types/Document.ts @@ -144,6 +144,7 @@ export interface OrdDocument { * A tombstone entry MAY be removed after a grace period of 31 days. */ tombstones?: Tombstone[]; + definitions?: InlineDefinitions; } /** * Information on the [system-instance](../index.md#system-instance) that this ORD document describes. @@ -916,7 +917,7 @@ export interface MetadataDefinitionAccessStrategy { /** * Defines the authentication/authorization strategy through which the referenced `resourceDefinitions` are accessible. */ - type: (string | "open" | "basic-auth" | "custom") & string; + type: (string | "open" | "embedded" | "basic-auth" | "custom") & string; /** * If the fixed `type` enum values need to be extended, an arbitrary `customType` can be provided. * @@ -3845,3 +3846,23 @@ export interface Tombstone { description?: string; [k: string]: unknown | undefined; } +/** + * A dictionary of inline [resource definitions](../index.md#resource-definition) for [push transport](../index.md#push-transport). + * + * When using push transport, resource definitions can be provided inline within the ORD document + * instead of being referenced via URLs and fetched separately. + * + * The **key** MUST be the URL path as referenced by resources via `resourceDefinitions[].url`. + * The **value** MUST be a string containing the raw content of the resource definition. + * + * The content is treated as an opaque text blob, preserving original formatting and whitespace. + * This works uniformly for all definition formats (OpenAPI JSON/YAML, AsyncAPI, WSDL, JSON Schema, etc.). + * + * This enables the aggregator to correlate inline definitions with the resources that reference them, + * keeping all metadata self-contained in a single push request. + * + * For pull transport, this property is typically not used as the aggregator fetches definitions via URLs. + */ +export interface InlineDefinitions { + [k: string]: string | undefined; +}