Skip to content
Merged
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
1 change: 1 addition & 0 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ value: '{{ index .steps "parse-request" "path_params" "id" }}'
|------|-------------|
| `webhook.sender` | Outbound webhook delivery with retry and dead letter |
| `notification.slack` | Slack notifications |
| `openapi` | OpenAPI v3 spec-driven route registration with request and response validation |
| `openapi.consumer` | OpenAPI spec consumer for external service integration |
| `openapi.generator` | OpenAPI spec generation from workflow config |

Expand Down
14 changes: 7 additions & 7 deletions example/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.26.0
replace github.com/GoCodeAlone/workflow => ../

require (
github.com/GoCodeAlone/modular v1.12.0
github.com/GoCodeAlone/modular v1.12.3
github.com/GoCodeAlone/workflow v0.0.0-00010101000000-000000000000
)

Expand All @@ -20,12 +20,12 @@ require (
cloud.google.com/go/storage v1.60.0 // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
github.com/DataDog/datadog-go/v5 v5.4.0 // indirect
github.com/GoCodeAlone/modular/modules/auth v1.12.0 // indirect
github.com/GoCodeAlone/modular/modules/cache v1.12.0 // indirect
github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.5.0 // indirect
github.com/GoCodeAlone/modular/modules/jsonschema v1.12.0 // indirect
github.com/GoCodeAlone/modular/modules/reverseproxy/v2 v2.5.0 // indirect
github.com/GoCodeAlone/modular/modules/scheduler v1.12.0 // indirect
github.com/GoCodeAlone/modular/modules/auth v1.14.0 // indirect
github.com/GoCodeAlone/modular/modules/cache v1.14.0 // indirect
github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.7.0 // indirect
github.com/GoCodeAlone/modular/modules/jsonschema v1.14.0 // indirect
github.com/GoCodeAlone/modular/modules/reverseproxy/v2 v2.7.0 // indirect
github.com/GoCodeAlone/modular/modules/scheduler v1.14.0 // indirect
github.com/GoCodeAlone/yaegi v0.17.1 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect
Expand Down
28 changes: 14 additions & 14 deletions example/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,20 @@ github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/datadog-go/v5 v5.4.0 h1:Ea3eXUVwrVV28F/fo3Dr3aa+TL/Z7Xi6SUPKW8L99aI=
github.com/DataDog/datadog-go/v5 v5.4.0/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw=
github.com/GoCodeAlone/modular v1.12.0 h1:C4tLfJe65rrUQsbtndiVfldtT8IRKZcHczNRNbBK4wo=
github.com/GoCodeAlone/modular v1.12.0/go.mod h1:ET7mlekRjkRq9mwJdWmaC2KDUWvjla2IqKVFrYO2JnY=
github.com/GoCodeAlone/modular/modules/auth v1.12.0 h1:eO4iq8tkz8W5sLKRSG5dC+ACITMtxZrtSJ+ReE3fKdA=
github.com/GoCodeAlone/modular/modules/auth v1.12.0/go.mod h1:D+yfkgN3MTkyl1xe8h2UL7uqB9Vj1lO3wUrscfnJ/NU=
github.com/GoCodeAlone/modular/modules/cache v1.12.0 h1:Ue6aXytFq1I+OnC3PcV2KlUg4lHiuGWH0Qq+v/lqyp0=
github.com/GoCodeAlone/modular/modules/cache v1.12.0/go.mod h1:kSaT8wNy/3YGmtIpDqPbW6MRqKOp2yc8a5MHdAag2CE=
github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.5.0 h1:K6X+X1sOq+lpI1Oa+XUzH+GlSRYJQfDTTcvMjZfkbFU=
github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.5.0/go.mod h1:Q0TpCFTtd0q20okDyi63ALS+1xmkYU4wNUOqwczyih0=
github.com/GoCodeAlone/modular/modules/jsonschema v1.12.0 h1:urGK8Xtwku4tn8nBeVZn9UqvldnCptZ3rLCXO21vSz4=
github.com/GoCodeAlone/modular/modules/jsonschema v1.12.0/go.mod h1:+/0p1alfSbhhshcNRId1HRRIupeu0DPC7BH8AYiBQ1I=
github.com/GoCodeAlone/modular/modules/reverseproxy/v2 v2.5.0 h1:zcF46oZ7MJFfZCmzqc1n9ZTw6wrTJSFr04yaz6EYKeo=
github.com/GoCodeAlone/modular/modules/reverseproxy/v2 v2.5.0/go.mod h1:ycmJYst0dgaeLYBDOFGYz3ZiVK0fVcbl59omBySpKis=
github.com/GoCodeAlone/modular/modules/scheduler v1.12.0 h1:kxeLUpFFZ2HWV5B7Ra1WaOr1DDee5G6kAZ6F1BUXX/Y=
github.com/GoCodeAlone/modular/modules/scheduler v1.12.0/go.mod h1:VpDSAU0Guj8geVz19YCSknyCJp0j3TMBaxLEYXedkZc=
github.com/GoCodeAlone/modular v1.12.3 h1:WcNqc1ZG+Lv/xzF8wTDavGIOeAvlV4wEd5HO2mVTUwE=
github.com/GoCodeAlone/modular v1.12.3/go.mod h1:nDdyW/eJu4gDFNueb6vWwLvti3bPHSZJHkWGiwEmi2I=
github.com/GoCodeAlone/modular/modules/auth v1.14.0 h1:Y+p4/HIcxkajlcNhcPlqpwAt1SCHjB4AaDMEys50E3I=
github.com/GoCodeAlone/modular/modules/auth v1.14.0/go.mod h1:fkwPn2svDsCHBI19gtUHxo064SL+EudjB+o7VjL9ug8=
github.com/GoCodeAlone/modular/modules/cache v1.14.0 h1:ykQRwXJGXaRtAsnW9Tgs0LvXExonkKr8P7XIHxPaYdY=
github.com/GoCodeAlone/modular/modules/cache v1.14.0/go.mod h1:tcIjHJHZ5fVU8sstILrXeVQgjpZcUkErnNjRaxkBSR8=
github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.7.0 h1:clGAyaOfyDc9iY63ONfZiHReVccVhK/yH19QEb14SSI=
github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.7.0/go.mod h1:0AnfWGVmrqyv91rduc6mrPqW6WQchDAa2WtM0Qmw/WA=
github.com/GoCodeAlone/modular/modules/jsonschema v1.14.0 h1:dCiPIO+NvJPizfCeUQqGXHD1WitOVYpKuL3fxMEjRlw=
github.com/GoCodeAlone/modular/modules/jsonschema v1.14.0/go.mod h1:5Hm+R9G41wwb0hKefx9+9PMqffjU1tA7roW3t3sTaLE=
github.com/GoCodeAlone/modular/modules/reverseproxy/v2 v2.7.0 h1:TtVD+tE8ABN98n50MFVyMAvMsBM4JE86KRgCRDzPDC4=
github.com/GoCodeAlone/modular/modules/reverseproxy/v2 v2.7.0/go.mod h1:N7d8aSV4eqr90qjlIOs/8EmW7avt9gwX06Uh+zKDr4s=
github.com/GoCodeAlone/modular/modules/scheduler v1.14.0 h1:JSrzo4FB7uGASExv+fCLRd6pXWULV1mJYvzmM9PzUeM=
github.com/GoCodeAlone/modular/modules/scheduler v1.14.0/go.mod h1:emkR2AnilabLJZv1rOTDO9eGpRBmZs487H00Lnp9jIc=
github.com/GoCodeAlone/yaegi v0.17.1 h1:aPAwU29L9cGceRAff02c5pjQcT5KapDB4fWFZK9tElE=
github.com/GoCodeAlone/yaegi v0.17.1/go.mod h1:z5Pr6Wse6QJcQvpgxTxzMAevFarH0N37TG88Y9dprx0=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c=
Expand Down
106 changes: 106 additions & 0 deletions example/openapi-jsonapi-articles.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# OpenAPI Response Validation — JSON:API Example
#
# This configuration demonstrates how the workflow engine validates API
# responses against an OpenAPI specification, including complex response
# formats like JSON:API (https://jsonapi.org/).
#
# Key features:
# - Request validation: incoming requests are checked against the spec
# - Response validation: outgoing responses are checked against the spec
# - response_action: "warn" logs violations, "error" rejects them with 500
#
# The JSON:API spec (specs/jsonapi-articles.yaml) defines a complex nested
# response envelope with required fields (data, type, id, attributes) that
# the engine validates automatically.

requires:
plugins:
- name: workflow-plugin-http
- name: workflow-plugin-openapi

modules:
# HTTP server
- name: jsonapi-server
type: http.server
config:
address: ":8096"

# HTTP router
- name: jsonapi-router
type: http.router
dependsOn:
- jsonapi-server

# OpenAPI module with response validation enabled
- name: articles-api
type: openapi
dependsOn:
- jsonapi-router
config:
spec_file: specs/jsonapi-articles.yaml
base_path: /api/v1
router: jsonapi-router
validation:
request: true
response: true
response_action: warn # "warn" = log and pass through; "error" = reject with 500
swagger_ui:
enabled: true
path: /docs

# Pipelines that generate JSON:API compliant responses.
# The OpenAPI response validation ensures these conform to the spec.
pipelines:
list-articles:
steps:
- name: build-response
type: step.set
config:
values:
response_status: 200
response_headers:
Content-Type: "application/vnd.api+json"
response_body: |
{
"data": [
{
"type": "articles",
"id": "1",
"attributes": {
"title": "Getting Started with Workflow Engine",
"body": "This article explains how to use the workflow engine...",
"created_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"author": {
"data": {"type": "people", "id": "42"}
}
}
}
],
"meta": {"total": 1, "page": 1, "per_page": 10},
"links": {"self": "/api/v1/articles"}
}

get-article:
steps:
- name: build-response
type: step.set
config:
values:
response_status: 200
response_headers:
Content-Type: "application/vnd.api+json"
response_body: |
{
"data": {
"type": "articles",
"id": "1",
"attributes": {
"title": "Getting Started with Workflow Engine",
"body": "This article explains how to use the workflow engine...",
"created_at": "2024-01-15T10:30:00Z"
}
},
"links": {"self": "/api/v1/articles/1"}
}
3 changes: 2 additions & 1 deletion example/openapi-petstore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ modules:
router: petstore-router
validation:
request: true
response: false
response: true
response_action: warn
swagger_ui:
enabled: true
path: /docs
189 changes: 189 additions & 0 deletions example/specs/jsonapi-articles.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
openapi: "3.0.0"
info:
title: Articles API (JSON:API)
version: "1.0.0"
description: |
A sample API that returns JSON:API (https://jsonapi.org/) compliant responses.
Demonstrates OpenAPI response validation against a complex JSON:API envelope.

paths:
/articles:
get:
operationId: listArticles
summary: List all articles
x-pipeline: list-articles
parameters:
- name: page[number]
in: query
required: false
schema:
type: integer
minimum: 1
- name: page[size]
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 100
responses:
"200":
description: A JSON:API compliant list of articles
content:
application/vnd.api+json:
schema:
type: object
required:
- data
properties:
data:
type: array
items:
type: object
required:
- type
- id
- attributes
properties:
type:
type: string
id:
type: string
attributes:
type: object
required:
- title
properties:
title:
type: string
body:
type: string
created_at:
type: string
relationships:
type: object
properties:
author:
type: object
properties:
data:
type: object
required:
- type
- id
properties:
type:
type: string
id:
type: string
included:
type: array
items:
type: object
required:
- type
- id
properties:
type:
type: string
id:
type: string
attributes:
type: object
meta:
type: object
properties:
total:
type: integer
page:
type: integer
per_page:
type: integer
links:
type: object
properties:
self:
type: string
first:
type: string
last:
type: string
next:
type: string
prev:
type: string

/articles/{id}:
get:
operationId: getArticle
summary: Get a single article
x-pipeline: get-article
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: A single article resource
content:
application/vnd.api+json:
schema:
type: object
required:
- data
properties:
data:
type: object
required:
- type
- id
- attributes
properties:
type:
type: string
id:
type: string
attributes:
type: object
required:
- title
properties:
title:
type: string
body:
type: string
created_at:
type: string
relationships:
type: object
links:
type: object
properties:
self:
type: string
"404":
description: Article not found
content:
application/vnd.api+json:
schema:
type: object
required:
- errors
properties:
errors:
type: array
minItems: 1
items:
type: object
required:
- status
- title
properties:
status:
type: string
title:
type: string
detail:
type: string
Loading
Loading