Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 105 additions & 4 deletions src/arazzo.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ The Arazzo Specification can articulate these workflows in a human-readable and
- [Format](#format)
- [Arazzo Description Structure](#arazzo-description-structure)
- [Data Types](#data-types)
- [Relative References in URLs](#relative-references-in-urls)
- [Parsing Documents](#parsing-documents)
- [Relative References in Arazzo Description URIs](#relative-references-in-arazzo-description-uris)
- [Schema](#schema)
Comment on lines +26 to 27
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you accidentally dropped "Relative References in API URLs" (that section looks good, btw, nice distinctions regarding Arazzo docs vs OAD docs vs APIs vs runtime expressions).

- [Arazzo Specification Object](#arazzo-specification-object)
- [Info Object](#info-object)
Expand All @@ -44,6 +45,7 @@ The Arazzo Specification can articulate these workflows in a human-readable and
- [Security Considerations](#security-considerations)
- [IANA Considerations](#iana-considerations)
- [Appendix A: Revision History](#appendix-a-revision-history)
- [Appendix B: Examples of Base URI Determination and Reference Resolution](#appendix-b-examples-of-base-uri-determination-and-reference-resolution)
<!-- /TOC -->

## Definitions
Expand Down Expand Up @@ -92,10 +94,67 @@ The formats defined are:
| `double` | number | |
| `password` | string | A hint to obscure the value. |

### Relative References in URLs
### Parsing Documents

Unless specified otherwise, all properties that are URLs MAY be relative references as defined by [RFC3986](https://tools.ietf.org/html/rfc3986#section-4.2).
Unless specified otherwise, relative references are resolved using the URL of the referring document.
Each document in an Arazzo Description MUST be fully parsed in order to locate possible reference targets before attempting to resolve references.
This includes the parsing requirements of [JSON Schema Specification Draft 2020-12](https://www.ietf.org/archive/id/draft-bhutton-json-schema-01.html#section-9), with appropriate modifications regarding base URIs as specified in [Relative References In URIs](#relative-references-in-arazzo-description-uris).
Reference targets include the Arazzo Object's [`$self`](#arazzoSelf) field (when present).

Implementations MUST NOT treat a reference as unresolvable before completely parsing all documents provided to the implementation as possible parts of the Arazzo Description.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's something analogous to say here about the url field in the Source Description Object, which (for OAS 3.2 and later) MUST examine provided OADs form a $self matching that url field. You arlready note further down that this field, if relative, MUST be resolved against the Arazzo document's base URI ($self if present) as a URI, so this is just the other end of it: once it's non-relative, you need to resolve it to a document by the target document's identity if that is different from its location.


If only the referenced part of a document is parsed when resolving a reference, implementations may miss the `$self` field or Source Description URIs, causing references to resolve to unintended locations. The resulting behavior of fragmentary parsing is _undefined_ and NOT RECOMMENDED.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This language is present in the OAS because in Swagger/OAS 2.0, the expectation was to parse targets in isolation (more or less... it's not quite spelled out but that's how it often worked). And then it was completely ambiguous in 3.0. So 3.1.1+ and 3.2 have this language to let people know something changed. If Arazzo documents were always parsed as whole documents, this is probably more confusing than helpful. I have no idea what Arazzo tools do today, though.


### Relative References in Arazzo Description URIs

URIs used as references within an Arazzo Description, including Source Description `url`, are resolved as _identifiers_, and described by this specification as **URIs**.

Unless specified otherwise, all fields that are URIs MAY be relative references as defined by [RFC3986 Section 4.2](https://tools.ietf.org/html/rfc3986#section-4.2).

#### Establishing the Base URI

Relative URI references are resolved using the appropriate base URI, which MUST be determined in accordance with [RFC3986 Section 5.1.1 – 5.1.4](https://tools.ietf.org/html/rfc3986#section-5.1.1).

The base URI for resolving relative references within an Arazzo Description is determined as follows:

- If the [`$self`](#arazzoSelf) field is present and is an absolute URI, the base URI is the `$self` URI.
- If the [`$self`](#arazzoSelf) field is present and is a relative URI-reference, the base URI is the result of resolving `$self` against the retrieval URI (or other applicable base URI per RFC3986 Section 5.1).
- If the [`$self`](#arazzoSelf) field is not present, the base URI is the retrieval URI of the Arazzo Description document.
Comment on lines +120 to +121
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wording makes it sound like the retrieval URI is the next place to look, which (per RFC3986) it is not. I'm nitpicking on this because it's a very persistent misconception, which is why the OAS says:

If $self is a relative URI reference, it is resolved against the next possible base URI source ([RFC3986] Section 5.1.2 – 5.1.4) before being used for the resolution of other relative URI references.

and then talks about the retrieval URI as the most common (but not next) place to find the base URI.

If you want use cases for the non-$self, non-retrieval URIs I can provide them.


For examples demonstrating base URI determination and reference resolution, see [Appendix B: Examples of Base URI Determination and Reference Resolution](#appendix-b-examples-of-base-uri-determination-and-reference-resolution).

#### Resolving URI Fragments

If a URI contains a fragment identifier, then the fragment MUST be resolved per the fragment resolution mechanism of the referenced document.

For JSON or YAML documents (including OpenAPI or AsyncAPI descriptions referenced via Source Descriptions), the fragment identifier SHOULD be interpreted as a JSON Pointer as per [RFC6901](https://tools.ietf.org/html/rfc6901).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this came from the OAS, but I just realized we have a slight bug here: Schema Objects can also declare plain name fragments. I'm not sure it's worth worrying about right now as I am not sure off the top of my head how to explain that part, but perhaps an issue to fix it before shipping? I just need to think on it for a little bit.


**Example:**

```yaml
sourceDescriptions:
- name: petstore
url: https://api.example.com/petstore.yaml
type: openapi

workflows:
- workflowId: example
steps:
- stepId: getPet
# Fragment '#/paths/~1pets/get' resolves via JSON Pointer
operationPath: '{$sourceDescriptions.petstore.url}#/paths/~1pets/get'
```

#### Relative URI References in CommonMark Fields

Relative references in CommonMark hyperlinks (such as those in `description` or `summary` fields) are resolved in their rendered context, which might differ from the context of the Arazzo Description.

#### Relative References in API URLs

API endpoints accessed during workflow execution are described by this specification as **URLs** (locations, not identifiers).

When [Step Objects](#step-object) reference API operations via `operationId` or `operationPath`, the actual API endpoint URL is determined by the OpenAPI description's Server Object, not by the Arazzo Description's base URI.

Runtime expressions may reference API URLs via `$url` during workflow execution, but these are evaluated at execution time, not during document parsing.

### Schema

Expand All @@ -110,6 +169,7 @@ This is the root object of the [Arazzo Description](#arazzo-description).
| Field Name | Type | Description |
| ---- | :----: | ---- |
| <a name="arazzoVersion"></a>arazzo | `string` | **REQUIRED**. This string MUST be the [version number](#versions) of the Arazzo Specification that the Arazzo Description uses. The `arazzo` field MUST be used by tooling to interpret the Arazzo Description. |
| <a name="arazzoSelf"></a>$self | `string` | A URI-reference for the Arazzo Description. This string MUST be in the form of a URI-reference as defined by [RFC3986 Section 4.1](https://tools.ietf.org/html/rfc3986#section-4.1). When present, this field provides the self-assigned URI of this Arazzo Description, which also serves as its base URI in accordance with [RFC3986 Section 5.1.1](https://tools.ietf.org/html/rfc3986#section-5.1.1) for resolving relative references within this document. The `$self` URI MUST NOT contain a fragment identifier. |
| <a name="arazzoInfo"></a>info | [Info Object](#info-object) | **REQUIRED**. Provides metadata about the workflows contain within the Arazzo Description. The metadata MAY be used by tooling as required. |
| <a name="arazzoSources"></a>sourceDescriptions | [[Source Description Object](#source-description-object)] | **REQUIRED**. A list of source descriptions (such as an OpenAPI description) this Arazzo Description SHALL apply to. The list MUST have at least one entry. |
| <a name="workflows"></a>workflows | [[Workflow Object](#workflow-object)] | **REQUIRED**. A list of workflows. The list MUST have at least one entry. |
Expand All @@ -121,6 +181,7 @@ This object MAY be extended with [Specification Extensions](#specification-exten

```yaml
arazzo: 1.0.1
$self: https://api.example.com/workflows/pet-purchase.arazzo.yaml
info:
title: A pet purchasing workflow
summary: This Arazzo Description showcases the workflow for how to purchase a pet through a sequence of API calls
Expand Down Expand Up @@ -1064,3 +1125,43 @@ The proposed MIME media type for Arazzo documents (e.g. workflows) that require
| --- | --- | --- |
| 1.0.1 | 2025-01-16 | Patch release of the Arazzo Specification 1.0.1 |
| 1.0.0 | 2024-05-29 | First release of the Arazzo Specification |

## Appendix B: Examples of Base URI Determination and Reference Resolution

This appendix provides concrete examples demonstrating how the [`$self`](#arazzoSelf) field, Source Description URLs, and relative references work together across different deployment scenarios.

### Base URI Within Content (Using `$self`)

Assume the following Arazzo document is retrieved from `file:///Users/dev/projects/workflows/purchase.arazzo.yaml`:

```yaml
arazzo: 1.1.0
$self: https://api.example.com/workflows/purchase.arazzo.yaml
info:
title: Pet Purchase Workflow
version: 1.0.0
sourceDescriptions:
- name: petstore
url: ../specs/petstore.yaml # Resolves to https://api.example.com/specs/petstore.yaml
type: openapi
```

The relative URL `../specs/petstore.yaml` resolves against the `$self` base URI (`https://api.example.com/workflows/`), producing `https://api.example.com/specs/petstore.yaml`, regardless of the retrieval URI.

### Base URI From the Retrieval URI (No `$self`)

If the same document does not define `$self`:
Comment on lines +1150 to +1153
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the other examples from OAS Appendix F are needed here, as the retrieval URI is not the only possible additional source.

Adding more sources shouldn't break compatibility, because in the exceedingly unlikely scenario that anyone was actually parsing something where there's an encapsulating entity (e.g. multipart/related hypermedia archive format), there's no obvious "retrieval URI" anyway, so they're doing something else not defined by Arazzo. I think the bits about handling $id in Schema Objects are relevant for you as well.


```yaml
arazzo: 1.1.0
# No $self field
info:
title: Pet Purchase Workflow
version: 1.0.0
sourceDescriptions:
- name: petstore
url: ../specs/petstore.yaml
type: openapi
```

Retrieved from `file:///Users/dev/projects/workflows/purchase.arazzo.yaml`, the relative URL resolves to `file:///Users/dev/projects/specs/petstore.yaml`.
5 changes: 5 additions & 0 deletions src/schemas/validation/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ properties:
description: The version number of the Arazzo Specification
type: string
pattern: '^1\.1\.\d+(-.+)?$'
$self:
type: string
format: uri-reference
$comment: MUST NOT contain a fragment
pattern: '^[^#]*$'
info:
$ref: '#/$defs/info'
sourceDescriptions:
Expand Down
14 changes: 14 additions & 0 deletions tests/schema/fail/invalid-self-fragment.arazzo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
arazzo: 1.1.0
$self: https://example.com/workflows/minimal-with-self.arazzo.yaml#/workflows/basicWorkflow
info:
title: Minimal Arazzo Example
version: 1.0.0
sourceDescriptions:
- name: exampleAPI
url: https://example.com/openapi.yaml
type: openapi
workflows:
- workflowId: basicWorkflow
steps:
- stepId: step1
operationId: getUsers
14 changes: 14 additions & 0 deletions tests/schema/pass/minimal-with-self.arazzo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
arazzo: 1.1.0
$self: https://example.com/workflows/minimal-with-self.arazzo.yaml
info:
title: Minimal Arazzo Example
version: 1.0.0
sourceDescriptions:
- name: exampleAPI
url: https://example.com/openapi.yaml
type: openapi
workflows:
- workflowId: basicWorkflow
steps:
- stepId: step1
operationId: getUsers
Loading