You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2022/03/17 09:52:03 UTC
[camel-kamelets] 01/02: chore: Add Kamelet rest-openapi-sink
This is an automated email from the ASF dual-hosted git repository.
acosentino pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-kamelets.git
commit f2263a4f562654a489ad7c7941c49e4404938c98
Author: Christoph Deppisch <cd...@redhat.com>
AuthorDate: Wed Mar 16 20:26:13 2022 +0100
chore: Add Kamelet rest-openapi-sink
New Kamelet loads OpenAPI specification from (http/https URL) and calls an operation on the HTTP service. The request is generated respecting the rules given in the OpenAPI specification (e.g. path parameters, Content-Type).
---
.github/workflows/yaks-tests.yaml | 1 +
kamelets/rest-openapi-sink.kamelet.yaml | 57 ++++
.../kamelets/rest-openapi-sink.kamelet.yaml | 57 ++++
test/rest-openapi-sink/openapi.json | 289 +++++++++++++++++++++
test/rest-openapi-sink/pet.json | 1 +
.../rest-openapi-sink-binding.yaml | 29 +++
test/rest-openapi-sink/rest-openapi-sink.feature | 52 ++++
test/rest-openapi-sink/yaks-config.yaml | 35 +++
8 files changed, 521 insertions(+)
diff --git a/.github/workflows/yaks-tests.yaml b/.github/workflows/yaks-tests.yaml
index 754f566..da874b9 100644
--- a/.github/workflows/yaks-tests.yaml
+++ b/.github/workflows/yaks-tests.yaml
@@ -102,6 +102,7 @@ jobs:
yaks run test/mail-sink $YAKS_RUN_OPTIONS
yaks run test/timer-source $YAKS_RUN_OPTIONS
yaks run test/earthquake-source $YAKS_RUN_OPTIONS
+ yaks run test/rest-openapi-sink $YAKS_RUN_OPTIONS
- name: YAKS Report
if: failure()
run: |
diff --git a/kamelets/rest-openapi-sink.kamelet.yaml b/kamelets/rest-openapi-sink.kamelet.yaml
new file mode 100644
index 0000000..35ee46e
--- /dev/null
+++ b/kamelets/rest-openapi-sink.kamelet.yaml
@@ -0,0 +1,57 @@
+# ---------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ---------------------------------------------------------------------------
+apiVersion: camel.apache.org/v1alpha1
+kind: Kamelet
+metadata:
+ name: rest-openapi-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Preview"
+ camel.apache.org/catalog.version: "main-SNAPSHOT"
+ camel.apache.org/kamelet.icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAlvUlEQVR4nOydd1xT19vAT3YgCSEM2VtEEVABERXFvWqXVbHaOuqve7nbam1tq7bWLldbq9bVum1t3VtxsEQFBFQ2yAwJISRkJ+9HLy9SNDfJzT33JprvX7fk5Jyn8uXec895zjl0g8EAHDjAGyrZATh4MnGI5QAKDrEcQMEhlgMoOMRyAAWHWA6g4BDLARQcYjmAAp3sABwQQVNT0/Xr1wvyC8rKymtrayUSiVqtBgCw2WyBQODr6xMaGtYzKrJPnz5cLheXFimOkfcnGJVKdfbsuZMnT+bfyjfnF02n02Jj48aMHT1w4EA63aqbjkOsJxOVSvXXwb/379/X3CzF8PUuXbpMe2Xa2LFjaDQatgAcYj2BpKdnrF2ztr6+3sp6Qk [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "HTTP"
+ labels:
+ camel.apache.org/kamelet.type: sink
+spec:
+ definition:
+ title: REST OpenAPI Sink
+ description: Load OpenAPI specification from URI and call an operation on the HTTP service. The request is generated respecting the rules given in the OpenAPI specification (e.g. path parameters, Content-Type).
+ required:
+ - specification
+ - operation
+ type: object
+ properties:
+ specification:
+ title: Specification URI
+ description: URI to the OpenApi specification file
+ type: string
+ example: "https://api.example.com/openapi.json"
+ pattern: "^(http|https|file|classpath)://.*"
+ operation:
+ title: Operation ID
+ description: The operation to call
+ type: string
+ dependencies:
+ - "camel:rest-openapi"
+ - "camel:http"
+ - "camel:kamelet"
+ - "camel:core"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - to: "rest-openapi:{{specification}}#{{operation}}"
diff --git a/library/camel-kamelets/src/main/resources/kamelets/rest-openapi-sink.kamelet.yaml b/library/camel-kamelets/src/main/resources/kamelets/rest-openapi-sink.kamelet.yaml
new file mode 100644
index 0000000..35ee46e
--- /dev/null
+++ b/library/camel-kamelets/src/main/resources/kamelets/rest-openapi-sink.kamelet.yaml
@@ -0,0 +1,57 @@
+# ---------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ---------------------------------------------------------------------------
+apiVersion: camel.apache.org/v1alpha1
+kind: Kamelet
+metadata:
+ name: rest-openapi-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Preview"
+ camel.apache.org/catalog.version: "main-SNAPSHOT"
+ camel.apache.org/kamelet.icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAlvUlEQVR4nOydd1xT19vAT3YgCSEM2VtEEVABERXFvWqXVbHaOuqve7nbam1tq7bWLldbq9bVum1t3VtxsEQFBFQ2yAwJISRkJ+9HLy9SNDfJzT33JprvX7fk5Jyn8uXec895zjl0g8EAHDjAGyrZATh4MnGI5QAKDrEcQMEhlgMoOMRyAAWHWA6g4BDLARQcYjmAAp3sABwQQVNT0/Xr1wvyC8rKymtrayUSiVqtBgCw2WyBQODr6xMaGtYzKrJPnz5cLheXFimOkfcnGJVKdfbsuZMnT+bfyjfnF02n02Jj48aMHT1w4EA63aqbjkOsJxOVSvXXwb/379/X3CzF8PUuXbpMe2Xa2LFjaDQatgAcYj2BpKdnrF2ztr6+3sp6Qk [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "HTTP"
+ labels:
+ camel.apache.org/kamelet.type: sink
+spec:
+ definition:
+ title: REST OpenAPI Sink
+ description: Load OpenAPI specification from URI and call an operation on the HTTP service. The request is generated respecting the rules given in the OpenAPI specification (e.g. path parameters, Content-Type).
+ required:
+ - specification
+ - operation
+ type: object
+ properties:
+ specification:
+ title: Specification URI
+ description: URI to the OpenApi specification file
+ type: string
+ example: "https://api.example.com/openapi.json"
+ pattern: "^(http|https|file|classpath)://.*"
+ operation:
+ title: Operation ID
+ description: The operation to call
+ type: string
+ dependencies:
+ - "camel:rest-openapi"
+ - "camel:http"
+ - "camel:kamelet"
+ - "camel:core"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - to: "rest-openapi:{{specification}}#{{operation}}"
diff --git a/test/rest-openapi-sink/openapi.json b/test/rest-openapi-sink/openapi.json
new file mode 100644
index 0000000..cae57a7
--- /dev/null
+++ b/test/rest-openapi-sink/openapi.json
@@ -0,0 +1,289 @@
+{
+ "openapi": "3.0.2",
+ "info": {
+ "title": "Swagger Petstore",
+ "version": "1.0.1",
+ "description": "This is a sample server Petstore server.",
+ "license": {
+ "name": "Apache 2.0",
+ "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
+ }
+ },
+ "servers": [
+ {
+ "url": "http://test-service/petstore"
+ }
+ ],
+ "paths": {
+ "/pet": {
+ "put": {
+ "requestBody": {
+ "description": "Pet object that needs to be added to the store",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ },
+ "required": true
+ },
+ "tags": [
+ "pet"
+ ],
+ "responses": {
+ "204": {
+ "description": "No content"
+ },
+ "400": {
+ "description": "Invalid ID supplied"
+ },
+ "404": {
+ "description": "Pet not found"
+ },
+ "405": {
+ "description": "Validation exception"
+ }
+ },
+ "operationId": "updatePet",
+ "summary": "Update an existing pet",
+ "description": ""
+ },
+ "post": {
+ "requestBody": {
+ "description": "Pet object that needs to be added to the store",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ },
+ "required": true
+ },
+ "tags": [
+ "pet"
+ ],
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "405": {
+ "description": "Invalid input"
+ }
+ },
+ "operationId": "addPet",
+ "summary": "Add a new pet to the store",
+ "description": ""
+ }
+ },
+ "/pet/{petId}": {
+ "get": {
+ "tags": [
+ "pet"
+ ],
+ "parameters": [
+ {
+ "name": "petId",
+ "description": "ID of pet to return",
+ "schema": {
+ "format": "int64",
+ "type": "integer"
+ },
+ "in": "path",
+ "required": true
+ },
+ {
+ "name": "verbose",
+ "description": "Output details",
+ "schema": {
+ "type": "boolean"
+ },
+ "in": "query",
+ "required": false
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ },
+ "description": "successful operation"
+ },
+ "400": {
+ "description": "Invalid ID supplied"
+ },
+ "404": {
+ "description": "Pet not found"
+ }
+ },
+ "operationId": "getPetById",
+ "summary": "Find pet by ID",
+ "description": "Returns a single pet"
+ },
+ "delete": {
+ "tags": [
+ "pet"
+ ],
+ "parameters": [
+ {
+ "name": "petId",
+ "description": "Pet id to delete",
+ "schema": {
+ "format": "int64",
+ "type": "integer"
+ },
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No content"
+ },
+ "400": {
+ "description": "Invalid ID supplied"
+ },
+ "404": {
+ "description": "Pet not found"
+ }
+ },
+ "operationId": "deletePet",
+ "summary": "Deletes a pet",
+ "description": ""
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Category": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "format": "int64",
+ "type": "integer"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "xml": {
+ "name": "Category"
+ }
+ },
+ "Tag": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "format": "int64",
+ "type": "integer"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "xml": {
+ "name": "Tag"
+ }
+ },
+ "Pet": {
+ "required": [
+ "category",
+ "name",
+ "status"
+ ],
+ "type": "object",
+ "properties": {
+ "id": {
+ "format": "int64",
+ "type": "integer"
+ },
+ "category": {
+ "$ref": "#/components/schemas/Category"
+ },
+ "name": {
+ "type": "string",
+ "example": "doggie"
+ },
+ "photoUrls": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "xml": {
+ "name": "photoUrl",
+ "wrapped": true
+ }
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Tag"
+ },
+ "xml": {
+ "name": "tag",
+ "wrapped": true
+ }
+ },
+ "status": {
+ "description": "pet status in the store",
+ "enum": [
+ "available",
+ "pending",
+ "sold"
+ ],
+ "type": "string"
+ }
+ },
+ "xml": {
+ "name": "Pet"
+ }
+ },
+ "ApiResponse": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "format": "int32",
+ "type": "integer"
+ },
+ "type": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ {
+ "name": "pet",
+ "description": "Everything about your Pets"
+ }
+ ]
+}
diff --git a/test/rest-openapi-sink/pet.json b/test/rest-openapi-sink/pet.json
new file mode 100644
index 0000000..1e9db09
--- /dev/null
+++ b/test/rest-openapi-sink/pet.json
@@ -0,0 +1 @@
+{ "id": ${petId}, "name": "fluffy", "category": {"id": ${petId}, "name": "dog"}, "photoUrls": [ "petstore/v3/photos/${petId}" ], "tags": [{"id": ${petId}, "name": "generated"}], "status": "available"}
diff --git a/test/rest-openapi-sink/rest-openapi-sink-binding.yaml b/test/rest-openapi-sink/rest-openapi-sink-binding.yaml
new file mode 100644
index 0000000..1f814cd
--- /dev/null
+++ b/test/rest-openapi-sink/rest-openapi-sink-binding.yaml
@@ -0,0 +1,29 @@
+apiVersion: camel.apache.org/v1alpha1
+kind: KameletBinding
+metadata:
+ name: rest-openapi-sink-binding
+spec:
+ source:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1alpha1
+ name: timer-source
+ properties:
+ period: 60000
+ message: '${pet}'
+ steps:
+ - ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1alpha1
+ name: insert-header-action
+ properties:
+ name: petId
+ value: ${petId}
+ sink:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1alpha1
+ name: rest-openapi-sink
+ properties:
+ specification: http://test-service.${YAKS_NAMESPACE}/petstore/openapi.json
+ operation: ${operation}
diff --git a/test/rest-openapi-sink/rest-openapi-sink.feature b/test/rest-openapi-sink/rest-openapi-sink.feature
new file mode 100644
index 0000000..64a73d3
--- /dev/null
+++ b/test/rest-openapi-sink/rest-openapi-sink.feature
@@ -0,0 +1,52 @@
+Feature: REST OpenAPI Kamelet sink
+
+ Background:
+ Given HTTP server timeout is 60000 ms
+ Given HTTP server "test-service"
+ Given variable petId is "1000"
+ Given load variable pet.json
+
+ Scenario: Create Http server
+ Given create Kubernetes service test-service
+
+ Scenario: Create Kamelet binding for addPet
+ Given Camel K resource polling configuration
+ | maxAttempts | 200 |
+ | delayBetweenAttempts | 2000 |
+ Given variable operation is "addPet"
+ When load KameletBinding rest-openapi-sink-binding.yaml
+ Then Camel K integration rest-openapi-sink-binding should be running
+
+ Scenario: Provide OpenAPI specification to Camel K integration
+ When receive GET /petstore/openapi.json
+ Then HTTP request header Content-Type is "application/json"
+ Then HTTP response body: citrus:readFile(classpath:openapi.json)
+ Then send HTTP 200 OK
+
+ Scenario: Verify proper addPet request message sent
+ Given expect HTTP request body: citrus:readFile(classpath:openapi.json)
+ And HTTP request header Content-Type is "application/json"
+ When receive POST /petstore/pet
+ And send HTTP 201 CREATED
+
+ Scenario: Remove resources
+ Given delete KameletBinding rest-openapi-sink-binding
+
+ Scenario: Create Kamelet binding for deletePet
+ Given variable operation is "deletePet"
+ When load KameletBinding rest-openapi-sink-binding.yaml
+ Then Camel K integration rest-openapi-sink-binding should be running
+
+ Scenario: Provide OpenAPI specification to Camel K integration
+ When receive GET /petstore/openapi.json
+ Then HTTP request header Content-Type is "application/json"
+ Then HTTP response body: citrus:readFile(classpath:openapi.json)
+ Then send HTTP 200 OK
+
+ Scenario: Verify proper deletePet request message sent
+ When receive DELETE /petstore/pet/${petId}
+ And send HTTP 204 NO_CONTENT
+
+ Scenario: Remove resources
+ Given delete KameletBinding rest-openapi-sink-binding
+ And delete Kubernetes service test-service
diff --git a/test/rest-openapi-sink/yaks-config.yaml b/test/rest-openapi-sink/yaks-config.yaml
new file mode 100644
index 0000000..9e2b89a
--- /dev/null
+++ b/test/rest-openapi-sink/yaks-config.yaml
@@ -0,0 +1,35 @@
+# ---------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ---------------------------------------------------------------------------
+
+config:
+ namespace:
+ temporary: false
+ runtime:
+ env:
+ - name: YAKS_CAMELK_AUTO_REMOVE_RESOURCES
+ value: false
+ - name: YAKS_KUBERNETES_AUTO_REMOVE_RESOURCES
+ value: false
+ resources:
+ - pet.json
+ - openapi.json
+ - rest-openapi-sink-binding.yaml
+ dump:
+ enabled: true
+ failedOnly: true
+ includes:
+ - app=camel-k