Webhooks4j
Small, simple and extendable Java library for messaging using webhooks and CDI events.
Status
Webhooks4j is currently under development.
Introduction
Webhooks4j is a simple Java library for implementing messaging using webhooks and event-sourcing, that does not need any infrastructure. It is meant to work for simple use cases where message brokers like Kafka are not needed. The library is based on the publish–subscribe pattern.
To subscribe to a topic, inject WebhookSubscriptions
and call the subscribe method:
import com.github.jensborch.webhooks.Webhook;
import com.github.jensborch.webhooks.subscriber.WebhookSubscriptions;
@Inject
WebhookSubscriptions subscriptions;
Webhook webhook = new Webhook(new URI("http://publisher-host/context-root"), new URI("http://subscriber-host/context-root"), "my-topic");
subscriptions.subscribe(webhook.state(Webhook.State.SUBSCRIBE));
To publish events, inject a WebhookPublisher
and call the publish method:
import com.github.jensborch.webhooks.WebhookEvent;
import com.github.jensborch.webhooks.publisher.WebhookPublisher;
@Inject
WebhookPublisher publisher;
Map<String, Object> eventData = new HashMap<>();
publisher.publish("my-topic", eventData));
To receive event use the CDI @Observes
annotation:
import com.github.jensborch.webhooks.WebhookEvent;
import com.github.jensborch.webhooks.WebhookEventTopic;
public void observe(@Observes @WebhookEventTopic("my-topic") final WebhookEvent event) {
//Process the event
}
The library is build using CDI 1.2, JAX-RS 2.0, Jackson and SLF4J. Usage of SLF4J version 1.6.0 or higher is assumed.
CDI 1.2 is used to be compatible with as many application servers as possible. This imposes some constraints and the solution thus currently do not support asynchronous CDI events and generic event data.
Getting started
Added the following dependency for a subscriber:
<dependency>
<groupId>com.github.jensborch.webhooks4j</groupId>
<artifactId>webhooks4j-subscriber</artifactId>
<version>0.6.5</version>
</dependency>
and
<dependency>
<groupId>com.github.jensborch.webhooks4j</groupId>
<artifactId>webhooks4j-subscriber</artifactId>
<version>0.6.5</version>
</dependency>
for a publisher.
For MongoDB support add:
<dependency>
<groupId>com.github.jensborch.webhooks4j</groupId>
<artifactId>webhooks4j-mongodb-subscriber</artifactId>
<version>0.6.5</version>
</dependency>
and/or
<dependency>
<groupId>com.github.jensborch.webhooks4j</groupId>
<artifactId>webhooks4j-mongodb-publisher</artifactId>
<version>0.6.5</version>
</dependency>
If MongoDB is not use for persistence, it is necessary to implement WebhookEventStatusRepository
and WebhookRepository
repository interfaces.
The MongoDB dependency requires POJO support, see examples below.
CDI producers must be defined for:
- javax.ws.rs.client.Client
- com.github.jensborch.webhooks.WebhookTTLConfiguration (required for MongoDB, otherwise optional)
- com.github.jensborch.webhooks.subscriber.WebhookSyncConfiguration (required only by subscriber module)
- com.mongodb.client.MongoDatabase (for MongoDB support)
and the following REST exposure classes:
- com.github.jensborch.webhooks.subscriber.SubscriberEventExposure
- com.github.jensborch.webhooks.subscriber.SubscriberWebhooksExposure
- com.github.jensborch.webhooks.publisher.PublisherEventExposure
- com.github.jensborch.webhooks.publisher.PublisherWebhookExposure
should be registered in your JAX-RS application class, depending on how you do JAX-RS configuration.
Additionally it might be necessary to configure Jackson by implementing ContextResolver, as the Jdk8Module
and JavaTimeModule
are required.
An example application using Quarkus can be found in the Maven test module.
Examples
JAX-RS client producer:
@Dependent
public class ClientProducer {
@Produces
@Publisher
public Client getPublisherClient() {
return ClientBuilder.newClient();
}
@Produces
@Subscriber
public Client getSubscriberClient() {
return ClientBuilder.newClient();
}
}
Mongo database producer:
@ApplicationScoped
public class WebhookMongoDBProducer {
@Inject
private MongoClient client;
@Produces
@Subscriber
@Publisher
public MongoDatabase mongoDatabase() {
return client.getDatabase("MyDatabase");
}
}
Note, this requires an additional CDI producer for MongoClient
, but it is possible to configure a MongoClient
directly instead. If no codecs for ZonedDateTime
and URI
exists, register the following codec class:
- com.github.jensborch.webhooks.mongodb.URICodec
- com.github.jensborch.webhooks.mongodb.ZonedDateTimeCode
JAX-RS application class:
@ApplicationPath("/")
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>(Arrays.asList(
MyExposure.class,
SubscriberEventExposure.class,
SubscriberWebhooksExposure.class,
PublisherEventExposure.class,
PublisherWebhookExposure.class,
));
return classes;
}
}
Jackson ContextResolver class:
@Provider
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
@Override
public ObjectMapper getContext(final Class<?> objectType) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jdk8Module());
objectMapper.registerModule(new JavaTimeModule());
return objectMapper;
}
}
Security
All endpoints are secured using JAX-RS roles. To access subscriber end-point, the subscriber role is needed. To access publisher endpoints the publisher role is need. The are some exceptions to this, as a publisher is allowed to POST callback events to a subscriber end-point. Refer to the Swagger documentation for the publisher and subscriber for details.
When creating the JAX-RS Client CDI producer, filters should be added to handle security correctly. A simple HTTP Basic access authentication filter can be found in the Maven test module.
Building
The Webhooks4j is build using Maven.
To build the application run the following command:
./mvnw package
Install the application in your local maven repository (required for running locally)
./mvnw install
Start the test application using:
./mvnw compile -pl test quarkus:dev
Call endpoints using VSCode RestClient or similar. See webhooks4j.http
Run mutation tests:
./mvnw eu.stamp-project:pitmp-maven-plugin:run
Release to Maven central:
./mvnw release:clean release:prepare -Prelease
./mvnw release:perform -Prelease