Skip to content
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

[Subscription API] OAS schema for filter expressions seems not to be correct #1038

Open
HenriKorver opened this issue Jul 25, 2022 · 9 comments

Comments

@HenriKorver
Copy link

HenriKorver commented Jul 25, 2022

Trying the understand the CE filter expressions, I have converted the OAS schema for the Subscription API to JSON Schema (see at the bottom of this message). This allows me to validate CE filter expressions in well-known tooling like Altova XMLSpy.

It appeared that correct CE filter expressions like

{
	"filters": [
		{
			"suffix": {
				"type": ".created",
				"subject": "/cloudevents/spec"
			}
		}
	]
}

are unfortunately not validated by the tool. The reason for this is the Filter schema object which matches everything. If this object is used in a oneOf construction than you always have more than two matches. This problem can easily be solved by removing the reference to the Filter object in each oneOf construction.

In the JSON schema which I derived from the OAS (see below), I have only included those parts that are relevant for filter expressions for compactness.

{
	"$schema": "http://json-schema.org/schema#",
	"description": "Comment describing your JSON Schema",
	"type": "object",
	"properties": {
		"filters": {
			"type": "array",
			"description": "This filter evaluates to 'true' if all contained filters are 'true'",
			"items": {
				"title": "Filter entry",
				"oneOf": [
					{
						"$ref": "#/definitions/Filter"
					},
					{
						"$ref": "#/definitions/AllFilter"
					},
					{
						"$ref": "#/definitions/AnyFilter"
					},
					{
						"$ref": "#/definitions/NotFilter"
					},
					{
						"$ref": "#/definitions/ExactFilter"
					},
					{
						"$ref": "#/definitions/PrefixFilter"
					},
					{
						"$ref": "#/definitions/SuffixFilter"
					},
					{
						"$ref": "#/definitions/SqlFilter"
					}
				]
			}
		}
	},
	"definitions": {
		"Filter": {
			"title": "Filter",
			"type": "object",
			"additionalProperties": true,
			"description": "A filter from a selection of multiple filter types and dialects"
		},
		"AllFilter": {
			"allOf": [
				{
					"$ref": "#/definitions/Filter"
				},
				{
					"type": "object",
					"properties": {
						"all": {
							"minItems": 1,
							"type": "array",
							"description": "This filter evaluates to 'true' if all contained filters are 'true'",
							"items": {
								"title": "Filter entry",
								"oneOf": [
									{
										"$ref": "#/definitions/Filter"
									},
									{
										"$ref": "#/definitions/AllFilter"
									},
									{
										"$ref": "#/definitions/AnyFilter"
									},
									{
										"$ref": "#/definitions/NotFilter"
									},
									{
										"$ref": "#/definitions/ExactFilter"
									},
									{
										"$ref": "#/definitions/PrefixFilter"
									},
									{
										"$ref": "#/definitions/SuffixFilter"
									}
								]
							}
						}
					},
					"additionalProperties": false,
					"description": "all filter"
				}
			]
		},
		"AnyFilter": {
			"allOf": [
				{
					"$ref": "#/definitions/Filter"
				},
				{
					"type": "object",
					"properties": {
						"any": {
							"minItems": 1,
							"type": "array",
							"description": "This filter evaluates to 'true' if any contained filters are 'true'",
							"items": {
								"title": "Filter entry",
								"oneOf": [
									{
										"$ref": "#/definitions/Filter"
									},
									{
										"$ref": "#/definitions/AllFilter"
									},
									{
										"$ref": "#/definitions/AnyFilter"
									},
									{
										"$ref": "#/definitions/NotFilter"
									},
									{
										"$ref": "#/definitions/ExactFilter"
									},
									{
										"$ref": "#/definitions/PrefixFilter"
									},
									{
										"$ref": "#/definitions/SuffixFilter"
									},
									{
										"$ref": "#/definitions/SqlFilter"
									}
								]
							}
						}
					},
					"additionalProperties": false,
					"description": "any filter"
				}
			]
		},
		"NotFilter": {
			"allOf": [
				{
					"$ref": "#/definitions/Filter"
				},
				{
					"type": "object",
					"properties": {
						"not": {
							"type": "object",
							"oneOf": [
								{
									"$ref": "#/definitions/Filter"
								},
								{
									"$ref": "#/definitions/AllFilter"
								},
								{
									"$ref": "#/definitions/AnyFilter"
								},
								{
									"$ref": "#/definitions/NotFilter"
								},
								{
									"$ref": "#/definitions/ExactFilter"
								},
								{
									"$ref": "#/definitions/PrefixFilter"
								},
								{
									"$ref": "#/definitions/SuffixFilter"
								},
								{
									"$ref": "#/definitions/SqlFilter"
								}
							]
						}
					},
					"additionalProperties": false,
					"description": "not filter"
				}
			]
		},
		"ExactFilter": {
			"allOf": [
				{
					"$ref": "#/definitions/Filter"
				},
				{
					"title": "exact filter",
					"type": "object",
					"properties": {
						"exact": {
							"$ref": "#/definitions/CloudEventsAttribute"
						}
					},
					"additionalProperties": false,
					"description": "This filter evaluates to 'true' if the 'value' exactly matches the value of the indicated CloudEvents context attribute"
				}
			]
		},
		"PrefixFilter": {
			"allOf": [
				{
					"$ref": "#/definitions/Filter"
				},
				{
					"title": "prefix filter",
					"type": "object",
					"properties": {
						"prefix": {
							"$ref": "#/definitions/CloudEventsAttribute"
						}
					},
					"additionalProperties": false,
					"description": "This filter evaluates to 'true' if the 'value' is a prefix of the value of the indicated CloudEvents context attribute"
				}
			]
		},
		"SuffixFilter": {
			"allOf": [
				{
					"$ref": "#/definitions/Filter"
				},
				{
					"title": "suffix filter",
					"type": "object",
					"properties": {
						"suffix": {
							"$ref": "#/definitions/CloudEventsAttribute"
						}
					},
					"additionalProperties": false,
					"description": "This filter evaluates to 'true' if the 'value' is a suffix of the value of the indicated CloudEvents context attribute"
				}
			]
		},
		"SqlFilter": {
			"allOf": [
				{
					"$ref": "#/definitions/Filter"
				},
				{
					"type": "object",
					"properties": {
						"sql": {
							"type": "string",
							"description": "The CESQL expression"
						}
					},
					"additionalProperties": true,
					"description": "CESQL filter"
				}
			]
		},
		"CloudEventsAttribute": {
			"type": "object",
			"description": "CloudEvents defined attributes.",
			"additionalProperties": {
				"type": "string"
			},
			"properties": {
				"id": {
					"type": "string",
					"description": "Identifies the event."
				},
				"source": {
					"type": "string",
					"description": "Identifies the context in which an event happened."
				},
				"specversion": {
					"type": "string",
					"description": "The version of the CloudEvents specification which the event uses."
				},
				"type": {
					"type": "string",
					"description": "Describes the type of event related to the originating occurrence."
				},
				"datacontenttype": {
					"type": "string",
					"description": "Content type of the data value."
				},
				"dataschema": {
					"type": "string",
					"description": "Identifies the schema that data adheres to."
				},
				"subject": {
					"type": "string",
					"description": "Describes the subject of the event in the context of the event producer."
				},
				"time": {
					"type": "string",
					"description": "Timestamp of when the occurrence happened."
				}
			}
		}
	}
}
@HenriKorver
Copy link
Author

HenriKorver commented Jul 25, 2022

Also references to the SqlFilter schema (see below) are a problem in the oneOf constructions in filter dialects because SqlFilter also matches "everything" (same problem as Filter schema object). This can be solved by setting additionalProperties to false.

"SqlFilter": {
			"allOf": [
				{
					"$ref": "#/definitions/Filter"
				},
				{
					"type": "object",
					"properties": {
						"sql": {
							"type": "string",
							"description": "The CESQL expression"
						}
					},
					"additionalProperties": true,
					"description": "CESQL filter"
				}
			]
		}

@duglin
Copy link
Collaborator

duglin commented Aug 9, 2022

@HenriKorver thanks! Would you be interested in submitting a PR ?

@github-actions
Copy link

This issue is stale because it has been open for 30 days with no
activity. Mark as fresh by updating e.g., adding the comment /remove-lifecycle stale.

@HenriKorver
Copy link
Author

/remove-lifecycle stale

@github-actions
Copy link

This issue is stale because it has been open for 30 days with no
activity. Mark as fresh by updating e.g., adding the comment /remove-lifecycle stale.

@HenriKorver
Copy link
Author

/remove-lifecycle stale

@github-actions
Copy link

This issue is stale because it has been open for 30 days with no
activity. Mark as fresh by updating e.g., adding the comment /remove-lifecycle stale.

@HenriKorver
Copy link
Author

/remove-lifecycle stale

@github-actions
Copy link

This issue is stale because it has been open for 30 days with no
activity. Mark as fresh by updating e.g., adding the comment /remove-lifecycle stale.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants