From f2e84b829dccd021a4758533dc6d360c1625a0b2 Mon Sep 17 00:00:00 2001 From: Ricardo Zanini Date: Thu, 5 Nov 2026 12:33:33 -0500 Subject: [PATCH 1/5] [Fix #1203] Clarify HTTP response headers access in documentation and CTK - Add an example and note to dsl-reference.md demonstrating how with.output: response can be used to access HTTP response headers and status code via output.as - Add CTK scenario for HTTP response output with output filtering - Add examples/call-http-output-headers.yaml workflow example Signed-off-by: Ricardo Zanini --- ctk/features/call.feature | 32 ++++++++++++++++++++++++++ dsl-reference.md | 24 +++++++++++++++++++ examples/call-http-output-headers.yaml | 27 ++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 examples/call-http-output-headers.yaml diff --git a/ctk/features/call.feature b/ctk/features/call.feature index 311d8f8c..7770a33a 100644 --- a/ctk/features/call.feature +++ b/ctk/features/call.feature @@ -62,6 +62,38 @@ Feature: Call Task And the workflow output should have properties 'request', 'request.method', 'request.uri', 'request.headers', 'headers', 'statusCode', 'content' And the workflow output should have properties 'content.id', 'content.name', 'content.status' + # Tests HTTP call using `response` output with output filtering + # Tests accessing response headers and content via output.as + Scenario: Call HTTP With Response Output And Output Filtering + Given a workflow with definition: + """yaml + document: + dsl: '1.0.3' + namespace: default + name: http-call-response-filtering + version: '1.0.0' + do: + - getPet: + call: http + with: + method: get + endpoint: + uri: https://petstore.swagger.io/v2/pet/{petId} + output: response + output: + as: + pet: .content + headers: .headers + """ + And given the workflow input is: + """yaml + petId: 1 + """ + When the workflow is executed + Then the workflow should complete + And the workflow output should have properties 'pet', 'headers' + And the workflow output should have properties 'pet.id', 'pet.name', 'pet.status' + # Tests HTTP call using `basic` authentication # Tests interpolated path parameters Scenario: Call HTTP Using Basic Authentication diff --git a/dsl-reference.md b/dsl-reference.md index c5ae5e62..704034ab 100644 --- a/dsl-reference.md +++ b/dsl-reference.md @@ -441,6 +441,7 @@ The [HTTP Call](#http-call) enables workflows to interact with external services ###### Examples +*Basic HTTP GET call:* ```yaml document: dsl: '1.0.4' @@ -455,6 +456,26 @@ do: endpoint: https://petstore.swagger.io/v2/pet/{petId} ``` +*Accessing HTTP response headers and content:* +```yaml +document: + dsl: '1.0.4' + namespace: test + name: http-response-example + version: '0.1.0' +do: + - getPet: + call: http + with: + method: get + endpoint: https://petstore.swagger.io/v2/pet/{petId} + output: response + output: + as: + pet: .content + headers: .headers +``` + ##### OpenAPI Call The [OpenAPI Call](#openapi-call) enables workflows to interact with external services described by [OpenAPI](https://www.openapis.org). @@ -2430,6 +2451,9 @@ Describes an HTTP response. | headers | `map[string, string]` | `no` | The HTTP response headers, if any. | | content | `any` | `no` | The HTTP response content, if any.
*If the request's content type is one of the following, should contain the deserialized response content. Otherwise, should contain the base-64 encoded response content, if any.*| +> [!NOTE] +> When `output: response` is specified on an [HTTP call](#http-call) or [OpenAPI call](#openapi-call), the task produces this structure as its raw output (`.`). Authors can then access response headers, status code, or content using runtime expressions in `output.as` or `export.as` (for example, `.headers` or `.content`). + #### Examples ```yaml diff --git a/examples/call-http-output-headers.yaml b/examples/call-http-output-headers.yaml new file mode 100644 index 00000000..f3b89d11 --- /dev/null +++ b/examples/call-http-output-headers.yaml @@ -0,0 +1,27 @@ +# yaml-language-server: $schema=../schema/workflow.yaml +document: + dsl: '1.0.4' + namespace: examples + name: http-output-headers + version: '1.0.0' +input: + schema: + format: json + document: + type: object + required: + - petId + properties: + petId: + type: integer +do: + - getPet: + call: http + with: + method: get + endpoint: https://petstore.swagger.io/v2/pet/{petId} + output: response + output: + as: + pet: .content + headers: .headers From 5e095fe0e6fa3abf84a25fe95532ca1ebe662fb0 Mon Sep 17 00:00:00 2001 From: Ricardo Zanini Date: Thu, 5 Nov 2026 15:19:49 -0500 Subject: [PATCH 2/5] Wrap output.as projections in runtime expressions and assert Content-Type in CTK Signed-off-by: Ricardo Zanini --- ctk/features/call.feature | 6 +++--- dsl-reference.md | 4 ++-- examples/call-http-output-headers.yaml | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ctk/features/call.feature b/ctk/features/call.feature index 7770a33a..92c69bfa 100644 --- a/ctk/features/call.feature +++ b/ctk/features/call.feature @@ -82,8 +82,8 @@ Feature: Call Task output: response output: as: - pet: .content - headers: .headers + pet: ${ .content } + headers: ${ .headers } """ And given the workflow input is: """yaml @@ -91,7 +91,7 @@ Feature: Call Task """ When the workflow is executed Then the workflow should complete - And the workflow output should have properties 'pet', 'headers' + And the workflow output should have properties 'pet', 'headers', 'headers.Content-Type' And the workflow output should have properties 'pet.id', 'pet.name', 'pet.status' # Tests HTTP call using `basic` authentication diff --git a/dsl-reference.md b/dsl-reference.md index 4fcdda6b..8aecb92a 100644 --- a/dsl-reference.md +++ b/dsl-reference.md @@ -472,8 +472,8 @@ do: output: response output: as: - pet: .content - headers: .headers + pet: ${ .content } + headers: ${ .headers } ``` ##### OpenAPI Call diff --git a/examples/call-http-output-headers.yaml b/examples/call-http-output-headers.yaml index f3b89d11..bb51a706 100644 --- a/examples/call-http-output-headers.yaml +++ b/examples/call-http-output-headers.yaml @@ -23,5 +23,5 @@ do: output: response output: as: - pet: .content - headers: .headers + pet: ${ .content } + headers: ${ .headers } From a6c9237fa376f076f05d0cf01d98353379b2e7ff Mon Sep 17 00:00:00 2001 From: Ricardo Zanini Date: Thu, 5 Nov 2026 15:28:59 -0500 Subject: [PATCH 3/5] Clarify HTTP status code mapping from status line in HTTP Response Signed-off-by: Ricardo Zanini --- ctk/features/call.feature | 7 ++++++- dsl-reference.md | 9 ++++++--- examples/call-http-output-headers.yaml | 1 + 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/ctk/features/call.feature b/ctk/features/call.feature index 92c69bfa..b6e2fb6f 100644 --- a/ctk/features/call.feature +++ b/ctk/features/call.feature @@ -84,6 +84,7 @@ Feature: Call Task as: pet: ${ .content } headers: ${ .headers } + status: ${ .statusCode } """ And given the workflow input is: """yaml @@ -91,8 +92,12 @@ Feature: Call Task """ When the workflow is executed Then the workflow should complete - And the workflow output should have properties 'pet', 'headers', 'headers.Content-Type' + And the workflow output should have properties 'pet', 'headers', 'headers.Content-Type', 'status' And the workflow output should have properties 'pet.id', 'pet.name', 'pet.status' + And the workflow output should have a 'status' property with value: + """yaml + 200 + """ # Tests HTTP call using `basic` authentication # Tests interpolated path parameters diff --git a/dsl-reference.md b/dsl-reference.md index 8aecb92a..5adc7211 100644 --- a/dsl-reference.md +++ b/dsl-reference.md @@ -474,6 +474,7 @@ do: as: pet: ${ .content } headers: ${ .headers } + status: ${ .statusCode } ``` ##### OpenAPI Call @@ -2440,19 +2441,21 @@ Describes an enpoint. ### HTTP Response -Describes an HTTP response. +Describes an HTTP response conforming to [RFC 9110 (HTTP Semantics)](https://www.rfc-editor.org/rfc/rfc9110.html). #### Properties | Property | Type | Required | Description | |----------|:----:|:--------:|-------------| | request | [`request`](#http-request) | `yes` | The HTTP request associated with the HTTP response. | -| statusCode | `integer` | `yes` | The HTTP response status code. | +| statusCode | `integer` | `yes` | The 3-digit numeric HTTP status code (e.g., `200`, `404`) parsed from the HTTP response status line ([RFC 9112 Section 3.1](https://www.rfc-editor.org/rfc/rfc9112.html#section-3.1)) or the `:status` pseudo-header field ([RFC 9113](https://www.rfc-editor.org/rfc/rfc9113.html)). | | headers | `map[string, string]` | `no` | The HTTP response headers, if any. | | content | `any` | `no` | The HTTP response content, if any.
*If the request's content type is one of the following, should contain the deserialized response content. Otherwise, should contain the base-64 encoded response content, if any.*| > [!NOTE] -> When `output: response` is specified on an [HTTP call](#http-call) or [OpenAPI call](#openapi-call), the task produces this structure as its raw output (`.`). Authors can then access response headers, status code, or content using runtime expressions in `output.as` or `export.as` (for example, `.headers` or `.content`). +> In HTTP/1.1 ([RFC 9112](https://www.rfc-editor.org/rfc/rfc9112.html)), the response status line is defined as `HTTP-version status-code [reason-phrase]` (e.g., `HTTP/1.1 200 OK`). In HTTP/2 ([RFC 9113](https://www.rfc-editor.org/rfc/rfc9113.html)) and HTTP/3 ([RFC 9114](https://www.rfc-editor.org/rfc/rfc9114.html)), status codes are carried in the `:status` pseudo-header and reason phrases are omitted. Runtimes map the status code to `statusCode` as an integer. +> +> When `output: response` is specified on an [HTTP call](#http-call) or [OpenAPI call](#openapi-call), the task produces this structure as its raw output (`.`). Authors can then access response headers, status code, or content using runtime expressions in `output.as` or `export.as` (for example, `${ .headers }`, `${ .statusCode }`, or `${ .content }`). #### Examples diff --git a/examples/call-http-output-headers.yaml b/examples/call-http-output-headers.yaml index bb51a706..55459bcc 100644 --- a/examples/call-http-output-headers.yaml +++ b/examples/call-http-output-headers.yaml @@ -25,3 +25,4 @@ do: as: pet: ${ .content } headers: ${ .headers } + status: ${ .statusCode } From e972343e79602f8a42375b8fa046f27ee8627ad1 Mon Sep 17 00:00:00 2001 From: Ricardo Zanini Date: Thu, 5 Nov 2026 15:31:22 -0500 Subject: [PATCH 4/5] Use statusCode property name consistently in examples and CTK Signed-off-by: Ricardo Zanini --- ctk/features/call.feature | 6 +++--- dsl-reference.md | 2 +- examples/call-http-output-headers.yaml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ctk/features/call.feature b/ctk/features/call.feature index b6e2fb6f..efcfcc04 100644 --- a/ctk/features/call.feature +++ b/ctk/features/call.feature @@ -84,7 +84,7 @@ Feature: Call Task as: pet: ${ .content } headers: ${ .headers } - status: ${ .statusCode } + statusCode: ${ .statusCode } """ And given the workflow input is: """yaml @@ -92,9 +92,9 @@ Feature: Call Task """ When the workflow is executed Then the workflow should complete - And the workflow output should have properties 'pet', 'headers', 'headers.Content-Type', 'status' + And the workflow output should have properties 'pet', 'headers', 'headers.Content-Type', 'statusCode' And the workflow output should have properties 'pet.id', 'pet.name', 'pet.status' - And the workflow output should have a 'status' property with value: + And the workflow output should have a 'statusCode' property with value: """yaml 200 """ diff --git a/dsl-reference.md b/dsl-reference.md index 5adc7211..74a8a9b5 100644 --- a/dsl-reference.md +++ b/dsl-reference.md @@ -474,7 +474,7 @@ do: as: pet: ${ .content } headers: ${ .headers } - status: ${ .statusCode } + statusCode: ${ .statusCode } ``` ##### OpenAPI Call diff --git a/examples/call-http-output-headers.yaml b/examples/call-http-output-headers.yaml index 55459bcc..8965cf3f 100644 --- a/examples/call-http-output-headers.yaml +++ b/examples/call-http-output-headers.yaml @@ -25,4 +25,4 @@ do: as: pet: ${ .content } headers: ${ .headers } - status: ${ .statusCode } + statusCode: ${ .statusCode } From 08c4eb56d11185b9422559edb5ebf774ed0eb26e Mon Sep 17 00:00:00 2001 From: Ricardo Zanini Date: Thu, 5 Nov 2026 15:57:37 -0500 Subject: [PATCH 5/5] Assert non-empty headers map in CTK without assuming header name casing Signed-off-by: Ricardo Zanini --- ctk/features/call.feature | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ctk/features/call.feature b/ctk/features/call.feature index efcfcc04..5e9cbb8a 100644 --- a/ctk/features/call.feature +++ b/ctk/features/call.feature @@ -84,6 +84,7 @@ Feature: Call Task as: pet: ${ .content } headers: ${ .headers } + hasHeaders: ${ (.headers | length) > 0 } statusCode: ${ .statusCode } """ And given the workflow input is: @@ -92,12 +93,16 @@ Feature: Call Task """ When the workflow is executed Then the workflow should complete - And the workflow output should have properties 'pet', 'headers', 'headers.Content-Type', 'statusCode' + And the workflow output should have properties 'pet', 'headers', 'hasHeaders', 'statusCode' And the workflow output should have properties 'pet.id', 'pet.name', 'pet.status' And the workflow output should have a 'statusCode' property with value: """yaml 200 """ + And the workflow output should have a 'hasHeaders' property with value: + """yaml + true + """ # Tests HTTP call using `basic` authentication # Tests interpolated path parameters