Skip to content
Open
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
5 changes: 5 additions & 0 deletions bom/camel-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@
<artifactId>camel-api</artifactId>
<version>4.24.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-apicurio-registry</artifactId>
<version>4.23.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-arangodb</artifactId>
Expand Down
5 changes: 5 additions & 0 deletions catalog/camel-allcomponents/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,11 @@
<artifactId>camel-amqp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-apicurio-registry</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-arangodb</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ alibaba-ots
alibaba-sls
alibaba-sms
amqp
apicurio-registry
arangodb
as2
asterisk
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ alibaba-ots-component
alibaba-sls-component
alibaba-sms-component
amqp-component
apicurio-registry-component
arangodb-component
as2-component
asn1-dataformat
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
= Apicurio Registry Component
:doctitle: Apicurio Registry
:shortname: apicurio-registry
:artifactid: camel-apicurio-registry
:description: Manage artifacts, versions, and groups in Apicurio Registry v3.
:since: 4.23
:supportlevel: Preview
:tabs-sync-option:
:component-header: Both producer and consumer are supported

*Since Camel {since}*

*{component-header}*

The Apicurio Registry component provides integration with https://www.apicur.io/registry/[Apicurio Registry] v3
using the https://github.com/Apicurio/apicurio-registry[Apicurio Registry Java SDK].

It supports CRUD operations on artifacts, groups, and versions, as well as schema validation
and polling for new artifact versions.

Maven users will need to add the following dependency to their `pom.xml`
for this component:

[source,xml]
----
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-apicurio-registry</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>
----

== URI format

----
apicurio-registry:groupId/artifactId[?options]
----

Where `groupId` and `artifactId` identify the registry artifact. Both are optional for
operations that do not require them (e.g., `searchArtifacts`, `createGroup`).

The first `/` separates the group ID from the artifact ID. Group IDs containing `/`
cannot be represented in the URI path. Producers can instead supply the group ID using
the `CamelApicurioRegistryGroupId` header, which overrides the URI value.

// component options: START
include::partial$component-configure-options.adoc[]
include::partial$component-endpoint-options.adoc[]
include::partial$component-endpoint-headers.adoc[]
// component options: END

== Producer Operations

The producer supports the following operations, set via the `operation` endpoint option or
the `CamelApicurioRegistryOperation` header:

[cols="1,3"]
|===
| Operation | Description

| `createArtifact` | Create a new artifact. Body contains the artifact content.
| `updateArtifact` | Create a new version of an existing artifact. Body contains the new content.
| `deleteArtifact` | Delete an artifact. Apicurio Registry 3.x disables artifact deletion by default; the registry must run with `apicurio.rest.deletion.artifact.enabled=true` (environment variable `APICURIO_REST_DELETION_ARTIFACT_ENABLED=true`), otherwise the operation fails with HTTP 405.
| `getArtifactContent` | Retrieve the content of an artifact version.
| `getArtifactMetadata` | Retrieve artifact metadata.
| `searchArtifacts` | Search for artifacts. See the "Searching artifacts" section below.
| `listVersions` | List all versions of an artifact, ordered by global ID. The component follows the registry's pagination and returns every page.
| `createGroup` | Create a new group.
| `testCompatibility` | Test schema compatibility (dry run). Returns `true`/`false` in the body.
| `validate` | Validate the message body against the artifact's rules (dry run). Throws `ApicurioRegistryValidationException` on failure when `failOnValidation=true`.
|===

Artifact content supplied to `createArtifact`, `updateArtifact`, `validate`, and
`testCompatibility` is converted to a string for the SDK's `VersionContent` model.
For AVRO and PROTOBUF, supply the schema definition, rather than serialized message data.
`getArtifactContent` returns a `byte[]`; the component closes the SDK response stream
before passing the content to the route.

`validate` and `testCompatibility` check a proposed artifact version against the registry's
configured rules without storing it. They do not validate application messages against a
stored schema. Authentication, connectivity, and other non-rule failures propagate as
exceptions, rather than returning a negative validation result.

Both operations set `CamelApicurioRegistryValidationErrors` to the rule violation details
when a check fails and clear any previous value before checking. Both set
`CamelApicurioRegistryValidationResult`; `testCompatibility` also returns the boolean result
in the body, while `validate` preserves the body.

Operations that act on a specific group or artifact fail with an `IllegalArgumentException`
when the group or artifact ID is set neither in the endpoint path nor in a header.

=== Searching artifacts

`searchArtifacts` filters by group ID and artifact ID (endpoint path or headers), and by the
`CamelApicurioRegistryArtifactName`, `CamelApicurioRegistryArtifactDescription`,
`CamelApicurioRegistryArtifactType` and `CamelApicurioRegistryLabels` headers. The body is an
`ArtifactSearchResults` holding one page of results and the total `count`.

Results are paged: the registry returns at most 20 artifacts unless you set
`CamelApicurioRegistrySearchLimit`. Use `CamelApicurioRegistrySearchOffset` to request further
pages, and `CamelApicurioRegistrySearchOrder` (`asc` or `desc`) and
`CamelApicurioRegistrySearchOrderBy` (`groupId`, `artifactId`, `createdOn`, `modifiedOn`,
`artifactType` or `name`) to sort them.

=== Headers from a consumer

The consumer sets the group, artifact and version headers on every exchange, and producers give
these headers precedence over their endpoint path. When a route forwards consumed versions to
another registry endpoint, remove them first so the producer uses its own path:

[source,java]
----
from("apicurio-registry:dev/orders?registryUrl={{dev.registry}}&fetchContent=true")
.removeHeaders("CamelApicurioRegistry*")
.to("apicurio-registry:prod/orders?registryUrl={{prod.registry}}&operation=updateArtifact");
----

== Consumer

The consumer polls the registry for new versions of the specified artifact. It tracks the last
seen `globalId` and only delivers new versions. Set the `delay` option to control the polling
interval (default: 500ms).

On first start, all existing versions of the artifact are emitted as exchanges. Subsequent polls
only deliver versions created after the consumer started. The watermark is held in memory and
resets on route/context restart.

Once it has a watermark, each poll first asks only for the newest version, so an idle poll
transfers a single entry. When there is something new, the consumer requests versions newest
first, one page at a time, and stops at the first version it has already seen. Paging is
offset-based: if a version is deleted while the consumer is reading pages, an older new version
can move to a page that was already read and be skipped.

All version states are listed, so `DRAFT` versions are delivered as soon as they appear. If the
registry allows changing the content of a version, a version is not delivered again after its
content changes. With `fetchContent=true`, `DISABLED` versions are skipped, because the registry
does not return their content. If the content of a version is not found (HTTP 404), the consumer
retries it on the next poll, since a registry node with replicated storage may not have the version
yet; if it is still not found, the version is skipped with a warning. Skipped versions are not
delivered again, even if a disabled version is enabled later.

If fetching content fails, or the route fails to process a version (including failures
handled by the error handler without being rethrown, such as with the default error handler),
the consumer stops the current poll without advancing the watermark. The failed version and any
newer ones are delivered again on the next poll. A version that always fails therefore blocks
newer versions. To skip such a version, mark the failure as handled, which lets the consumer
advance past it:

[source,java]
----
onException(MyPermanentException.class).handled(true).to("log:skipped");
----

When `fetchContent=true`, the consumer fetches the version content and sets it as a `byte[]` exchange body,
closing the SDK response stream before processing the exchange.
Otherwise, the version metadata object is set as the body.

== Examples

=== Create an artifact

[tabs]
====
Java::
+
[source,java]
----
from("direct:create")
.setBody(constant("{\"type\":\"record\",\"name\":\"Test\",\"fields\":[]}"))
.to("apicurio-registry:myGroup/myArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=createArtifact&artifactType=AVRO");
----

XML::
+
[source,xml]
----
<route>
<from uri="direct:create"/>
<setBody><constant>{"type":"record","name":"Test","fields":[]}</constant></setBody>
<to uri="apicurio-registry:myGroup/myArtifact?registryUrl=http://localhost:8080/apis/registry/v3&amp;operation=createArtifact&amp;artifactType=AVRO"/>
</route>
----

YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:create
steps:
- setBody:
constant: '{"type":"record","name":"Test","fields":[]}'
- to:
uri: apicurio-registry:myGroup/myArtifact
parameters:
registryUrl: http://localhost:8080/apis/registry/v3
operation: createArtifact
artifactType: AVRO
----
====

=== Poll for new versions

[tabs]
====
Java::
+
[source,java]
----
from("apicurio-registry:myGroup/myArtifact?registryUrl=http://localhost:8080/apis/registry/v3&delay=5000")
.log("New version detected: ${header.CamelApicurioRegistryVersion}")
.to("log:newVersions");
----

XML::
+
[source,xml]
----
<route>
<from uri="apicurio-registry:myGroup/myArtifact?registryUrl=http://localhost:8080/apis/registry/v3&amp;delay=5000"/>
<log message="New version detected: ${header.CamelApicurioRegistryVersion}"/>
<to uri="log:newVersions"/>
</route>
----

YAML::
+
[source,yaml]
----
- route:
from:
uri: apicurio-registry:myGroup/myArtifact
parameters:
registryUrl: http://localhost:8080/apis/registry/v3
delay: 5000
steps:
- log:
message: "New version detected: ${header.CamelApicurioRegistryVersion}"
- to:
uri: log:newVersions
----
====

=== Validate a proposed schema version

[source,java]
----
from("direct:validateSchema")
.doTry()
.to("apicurio-registry:my-group/order-schema?operation=validate&registryUrl=http://localhost:8080/apis/registry/v3")
.to("direct:publishSchema")
.doCatch(ApicurioRegistryValidationException.class)
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(400))
.setBody(simple("${exception.validationErrors}"))
.end();
----

== Connection settings

All endpoints of the component share a single Vert.x instance for their SDK clients. The
component creates it on first use and closes it when the component stops. To reuse an existing
Vert.x instance, set the `vertx` component option or bind a single `Vertx` bean in the registry;
the component does not close a Vert.x instance it did not create.

A client supplied through `registryClient` remains caller-owned;
the caller is responsible for its underlying HTTP resources.

For HTTPS registries that use a private CA or require client certificates (mTLS), configure
`sslContextParameters`. Use `proxyHost`, `proxyPort`, `proxyUsername` and `proxyPassword` to go
through an HTTP proxy. Both settings also apply to the OAuth2 token endpoint.

== Authentication

The component supports three authentication modes via the `authType` option:

* `none` (default): No authentication.
* `basic`: Basic authentication using `username` and `password`.
* `oidc`: OAuth2/OIDC using `tokenEndpoint`, `clientId`, `clientSecret`, and optionally `scope`.

Example with OIDC:

[source,java]
----
from("direct:secured")
.to("apicurio-registry:myGroup/myArtifact?registryUrl=http://localhost:8080/apis/registry/v3"
+ "&operation=getArtifactContent"
+ "&authType=oidc"
+ "&tokenEndpoint=http://keycloak:8080/realms/registry/protocol/openid-connect/token"
+ "&clientId=registry-client&clientSecret=secret");
----
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,17 @@
"version" : "4.24.0-SNAPSHOT",
"serviceVersion" : "camel",
"uiSupported" : false
}, {
"service" : "org.apache.camel.test.infra.apicurio.registry.services.ApicurioRegistryInfraService",
"description" : "Apicurio Registry is an API/Schema registry",
"implementation" : "org.apache.camel.test.infra.apicurio.registry.services.ApicurioRegistryLocalContainerInfraService",
"alias" : [ "apicurio-registry" ],
"aliasImplementation" : [ ],
"groupId" : "org.apache.camel",
"artifactId" : "camel-test-infra-apicurio-registry",
"version" : "4.23.0-SNAPSHOT",
"serviceVersion" : "3.3.0",
"uiSupported" : false
}, {
"service" : "org.apache.camel.test.infra.postgres.services.PostgresInfraService",
"description" : "PostgreSQL with pgvector extension for vector similarity search",
Expand Down
Loading
Loading