This is an automated email from the ASF dual-hosted git repository.
cdeppisch pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-jbang-examples.git
The following commit(s) were added to refs/heads/main by this push:
new d25b121 fix(#6): Add Open API server example
d25b121 is described below
commit d25b121fa1daf949a26cbf5ecfc0acead9c1ef75
Author: Christoph Deppisch <[email protected]>
AuthorDate: Thu Jan 9 16:59:40 2025 +0100
fix(#6): Add Open API server example
---
.github/workflows/build.yml | 4 +
openapi/server/README.adoc | 79 ++++++++
openapi/server/application.properties | 19 ++
openapi/server/examples/pet/1000.json | 18 ++
openapi/server/petstore-api.json | 299 +++++++++++++++++++++++++++++
openapi/server/petstore.camel.yaml | 6 +
openapi/server/test/examples/pet/1000.json | 18 ++
openapi/server/test/jbang.properties | 2 +
openapi/server/test/petstore-api.json | 299 +++++++++++++++++++++++++++++
openapi/server/test/petstore.camel.it.yaml | 27 +++
10 files changed, 771 insertions(+)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 3343cb9..740b616 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -66,6 +66,10 @@ jobs:
pushd mqtt/test
jbang citrus@citrusframework/citrus run mqtt.camel.it.yaml
popd
+
+ pushd openapi/server/test
+ jbang citrus@citrusframework/citrus run petstore.camel.it.yaml
+ popd
- uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874
# v4.4.0
if: always()
with:
diff --git a/openapi/server/README.adoc b/openapi/server/README.adoc
new file mode 100644
index 0000000..82bc120
--- /dev/null
+++ b/openapi/server/README.adoc
@@ -0,0 +1,79 @@
+= Open API server
+
+This example uses an Open API specification as a base for creating a REST
service in Camel.
+The Camel route is configured to implement the operations declared in the Open
API specification.
+
+== Install Camel JBang
+
+include::../../install.adoc[see installation]
+
+== How to run
+
+Then you can run the Camel integration using:
+
+[source,shell]
+----
+camel run petstore-api.json application.properties petstore.camel.yaml
+----
+
+And then from another terminal (or run the integration with `--background`
option),
+then send a message to the REST service.
+
+Just call the petstore REST API to retrieve a pet like this:
+
+[source,shell]
+----
+$ curl -i http://localhost:8080/petstore/pet/1000
+HTTP/1.1 200 OK
+petId: 1000
+transfer-encoding: chunked
+Content-Type: application/json
+
+{
+ "id": 1000,
+ "name": "fluffy",
+ "category": {
+ "id": 1000,
+ "name": "dog"
+ },
+ "photoUrls": [
+ "petstore/v3/photos/1000"
+ ],
+ "tags": [
+ {
+ "id": 1000,
+ "name": "generated"
+ }
+ ],
+ "status": "available"
+}
+
+----
+
+The REST service in Camel is configured to load example response data from a
directory (`camel.component.rest-openapi.mockIncludePattern =
file:examples/**,classpath:examples/**`).
+
+== Integration testing
+
+The example provides an automated integration test (`pestore.camel.it.yaml`)
that you can run with the https://citrusframework.org/[Citrus] test framework.
+Please make sure to install Citrus as a JBang application (see
link:../../install-citrus.adoc[Citrus installation guide]).
+
+You can run the test with:
+
+[source,shell]
+----
+cd test
+citrus run pestore.camel.it.yaml
+----
+
+The test prepares the complete infrastructure and starts the Camel route
automatically via JBang.
+The Citrus test loads the Open API specification from the Camel service and
uses the rules in that specification to verify the response data.
+
+== Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+https://camel.apache.org/community/support/[let us know].
+
+We also love contributors, so
+https://camel.apache.org/community/contributing/[get involved] :-)
+
+The Camel riders!
diff --git a/openapi/server/application.properties
b/openapi/server/application.properties
new file mode 100644
index 0000000..0081528
--- /dev/null
+++ b/openapi/server/application.properties
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+camel.component.rest-openapi.mockIncludePattern =
file:examples/**,classpath:examples/**
+camel.server.enabled=true
diff --git a/openapi/server/examples/pet/1000.json
b/openapi/server/examples/pet/1000.json
new file mode 100644
index 0000000..eee6fad
--- /dev/null
+++ b/openapi/server/examples/pet/1000.json
@@ -0,0 +1,18 @@
+{
+ "id": 1000,
+ "name": "fluffy",
+ "category": {
+ "id": 1000,
+ "name": "dog"
+ },
+ "photoUrls": [
+ "petstore/v3/photos/1000"
+ ],
+ "tags": [
+ {
+ "id": 1000,
+ "name": "generated"
+ }
+ ],
+ "status": "available"
+}
diff --git a/openapi/server/petstore-api.json b/openapi/server/petstore-api.json
new file mode 100644
index 0000000..89f9c02
--- /dev/null
+++ b/openapi/server/petstore-api.json
@@ -0,0 +1,299 @@
+{
+ "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": "{scheme}://{host}/{basePath}",
+ "variables": {
+ "scheme": {
+ "enum": [
+ "https",
+ "http"
+ ],
+ "default": "http"
+ },
+ "host": {
+ "default": "localhost:8080"
+ },
+ "basePath": {
+ "default": "/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": {
+ "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/openapi/server/petstore.camel.yaml
b/openapi/server/petstore.camel.yaml
new file mode 100644
index 0000000..1ae795f
--- /dev/null
+++ b/openapi/server/petstore.camel.yaml
@@ -0,0 +1,6 @@
+- restConfiguration:
+ clientRequestValidation: true
+ apiContextPath: openapi
+- rest:
+ openApi:
+ specification: petstore-api.json
diff --git a/openapi/server/test/examples/pet/1000.json
b/openapi/server/test/examples/pet/1000.json
new file mode 100644
index 0000000..eee6fad
--- /dev/null
+++ b/openapi/server/test/examples/pet/1000.json
@@ -0,0 +1,18 @@
+{
+ "id": 1000,
+ "name": "fluffy",
+ "category": {
+ "id": 1000,
+ "name": "dog"
+ },
+ "photoUrls": [
+ "petstore/v3/photos/1000"
+ ],
+ "tags": [
+ {
+ "id": 1000,
+ "name": "generated"
+ }
+ ],
+ "status": "available"
+}
diff --git a/openapi/server/test/jbang.properties
b/openapi/server/test/jbang.properties
new file mode 100644
index 0000000..8ff5693
--- /dev/null
+++ b/openapi/server/test/jbang.properties
@@ -0,0 +1,2 @@
+# Declare required additional dependencies
+run.deps=org.citrusframework:citrus-camel:4.5.0,org.citrusframework:citrus-openapi:4.5.0,io.vertx:vertx-core:4.5.11
diff --git a/openapi/server/test/petstore-api.json
b/openapi/server/test/petstore-api.json
new file mode 100644
index 0000000..89f9c02
--- /dev/null
+++ b/openapi/server/test/petstore-api.json
@@ -0,0 +1,299 @@
+{
+ "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": "{scheme}://{host}/{basePath}",
+ "variables": {
+ "scheme": {
+ "enum": [
+ "https",
+ "http"
+ ],
+ "default": "http"
+ },
+ "host": {
+ "default": "localhost:8080"
+ },
+ "basePath": {
+ "default": "/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": {
+ "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/openapi/server/test/petstore.camel.it.yaml
b/openapi/server/test/petstore.camel.it.yaml
new file mode 100644
index 0000000..d2d3576
--- /dev/null
+++ b/openapi/server/test/petstore.camel.it.yaml
@@ -0,0 +1,27 @@
+name: petstore-test
+description: Sample test in YAML
+variables:
+ - name: petId
+ value: 1000
+actions:
+ - camel:
+ jbang:
+ run:
+ integration:
+ name: "petstore"
+ file: "../petstore.camel.yaml"
+ systemProperties:
+ file: "../application.properties"
+ resources:
+ - "petstore-api.json"
+ - openapi:
+ specification: "http://localhost:8080/openapi"
+ client: "http://localhost:8080/petstore"
+ sendRequest:
+ operation: getPetById
+ - openapi:
+ specification: "http://localhost:8080/openapi"
+ client: "http://localhost:8080/petstore"
+ receiveResponse:
+ operation: getPetById
+ status: 200