-
Notifications
You must be signed in to change notification settings - Fork 6
Support Push based transport mode #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
1f98684
68f7c5a
46ba867
699edbc
44365c8
6dddc33
92ea368
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does "designed for" mean "limited to"? Embedded resources seem equally useful in pull mode — a provider might want to serve a self-contained ORD document without requiring the aggregator to make additional HTTP requests for resource definitions. IMO push vs. pull is purely a transport concern and shouldn't dictate what the document can contain. |
||
|
|
||
| - 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 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should atomic "all-or-nothing" semantics be a hard requirement here? If a push partially fails (e.g. some resource definitions are invalid), should the aggregator reject the entire payload or accept the valid parts? This needs an explicit statement in the spec — partial updates could leave an aggregator in an inconsistent state, but strict atomicity may be impractical for large payloads.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, so far we left it to the aggregator as an implementation detail. I think there's some "oppinion" in how strong this is fulfilled. I'll keep it in mind, but defining this would be probably a general enhancement, not just for the push based appraoch. |
||
|
|
||
| ## 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 | | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This proposal feels underspecified for enabling reusable, interoperable aggregators. For anyone to build a generic aggregator that works across providers, there needs to be a standard push protocol — not just a payload shape. Concretely, that means defining:
Without these being standardized, every aggregator will implement its own variant and the push mechanism won't be reusable — which defeats the purpose.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's on point. Right now it's underdefined, reason is that we would need to build / prototype this along with defining here in the spec and that hasn't happened yet. I agree that those questions need to be clarified. On the async side, it comes with some drawbacks like not getting errors / problems quick enough. But since the aggregator needs a bit time to validate, maybe it's more realistic to batch more and then also receive validation asynchronously later. It would be a more complicated pattern than just sync push with direct error feedback. |
||
|
|
||
| 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. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no need to limit this to push transport. Most aggregator implementations will have a single document-handling pipeline regardless of how the document arrived — the transport layer should be transparent to the processing logic. Artificially restricting embedded resources to push mode adds complexity for no benefit.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, it would also make sense on pull. Conceptually, it would of course work for both transport modes. |
||
|
|
||
| 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. | ||
|
|
||
| <!-- The aggregator MAY advertise its push API capabilities via its own ORD configuration endpoint at `/.well-known/open-resource-discovery`. | ||
| The aggregator configuration MAY include: | ||
| - The URL of the push API endpoint | ||
| - Supported access strategies for authenticating providers | ||
| - Description and documentation links for onboarding | ||
|
|
||
|
|
||
| Example aggregator configuration: | ||
| ```json | ||
| { | ||
| "openResourceDiscoveryAggregator": { | ||
| "supportedVersions": ["1.14", "1.15"], | ||
| "supportedTransportModes": { | ||
| "push": { | ||
| "publishDocumentEndpoint": "/ord-publishing-api/v1/documents", | ||
| "validationResultsEndpoint": "/ord-publishing-api/v1/validationResults", | ||
| "accessStrategies": [ | ||
| { | ||
| "type": "sap:oauth-client-credentials:v1", | ||
| "description": "Contact ord-support@example.com to request push credentials.", | ||
| "documentationLink": "https://help.example.com/ord/push-onboarding" | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` --> | ||
|
|
||
| ###### 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 <token> | ||
|
|
||
| { | ||
| "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. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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\"}}}}}}}}}}}" | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why inline instead of a ZIP file?
Embedded resources could easily push the document past the 2MB limit. Also it may greatly increase the memory requirements for parsing the document.
Example:
With a zip file you can push an arbitrary amount of resource definitions (and even ORD documents if it makes sense).
All files should be listed in the manifest. It acts as the document served at the "well-known" endpoint.
Optionally it can contain signatures, hashes, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I also thought about it. It would be a different approach, then we don't need embedding. Instead we use relative file links.
Those ZIP files could get quite big though and I'm not sure how ideal it is with regards to HTTP protocol which already does compression as part of the transport.
I see another alternative: POST/PUT all the files as part of a transaction, which then can be committed via separate action on the API. Then there can be a GET on the transaction to also receive feedback.
This would be closer to HTTP conventions and reuse of how the protocol works, also would be more async. It requires some transaction management on aggregator side, though.