taymyr / lagom-extensions

Utilities for Lagom framework

GitHub

Gitter Gitter_RU Build Status Javadocs Codecov Maven Central

Lagom Java API Extensions

This library is an extension of Lagom Java/Scala DSL.

Note: We try not to change the API, but before the release of stable version 1.0.0 API may be changed.

Versions compatibility

Lagom Extensions Lagom Scala
0.+ 1.5.+
1.6.+
2.12
2.13

Features

Message Protocols (Java ✓ / Scala ✗ )

MessageProtocols have constants for most used message protocols (application/json, application/json; charset=utf-8, etc). See Javadoc for more information.

Response Headers (Java ✓ / Scala ✗ )

ResponseHeaders have constants of ResponseHeader and utilities functions for instantiation Pair<ResponseHeader, T>.

Code example:

// Lagom
(headers, request) -> { 
    ...
    return completedFuture(
        new Pair<>(
            ResponseHeader.OK.withProtocol(MessageProtocol.fromContentTypeHeader(Optional.of("application/json"))), 
            result
        )
    );
};

// Lagom Extensions
(headers, request) -> { 
    ...
    return completedFuture(okJson(result));
};

Simple Kafka Producer (Java ✓ / Scala ✗ )

At this moment Lagom (1.4.+) doesn't provide any framework-level API to produce records to topics declared in subscriber-only service descriptors. In such cases, we need to use the underlying Alpakka Kafka directly to publish.

  1. It is useful to place TopicDescriptor in the subscriber-only service descriptor.
public interface FooTopicService extends Service {

    TopicDescriptor<FooTopicRecord> FOO_TOPIC = TopicDescriptor.of("foo-topic", FooTopicRecord.class);
    
    Topic<String> fooTopic();

    @Override
    default Descriptor descriptor() {
        return named("foo-topic-service")
            .withTopics(topic(FOO_TOPIC.getId(), this::fooTopic))
            .withAutoAcl(true);
    }
}

At the topic call declaration you may also specify .withProperties(KafkaProperties.partitionKeyStrategy, ...) to support topic record key generation (see Lagom docs).

  1. You should inject SimpleTopicProducersRegistry and register producers for the declared topics (other details are intentionally omitted)
public class BarServiceImpl implements BarService {

    private SimpleTopicProducersRegistry registry;

    @Inject
    public BarServiceImpl(FooTopicService fooTopicService, SimpleTopicProducersRegistry registry) {
        this.registry = registry.register(fooTopicService);
    }
}
  1. Now you able to retrieve producer for the desired topic from the registry and to publish record easily.
@Override
public ServiceCall<FooTopicRecord, NotUsed> publishToFoo() {
    return fooTopicRecord ->
            registry.get(FooTopicService.FOO_TOPIC).publish(fooTopicRecord)
                .thenApply( x -> NotUsed.getInstance() );
}
  1. SimpleTopicProducer relies on akka.kafka.producer config by default (see Akka producer, Akka source). You also may provide a separate config for each topic producer. In that case, config path should be <topic-name>.producer instead of akka.kafka.producer.
foo-topic.producer {
  # Tuning parameter of how many sends that can run in parallel.
  parallelism = 100

  # Duration to wait for `KafkaConsumer.close` to finish.
  close-timeout = 60s
  
  # Fully qualified config path which holds the dispatcher configuration
  # to be used by the producer stages. Some blocking may occur.
  # When this value is empty, the dispatcher configured for the stream
  # will be used.
  use-dispatcher = "akka.kafka.default-dispatcher"

  # The time interval to commit a transaction when using the `Transactional.sink` or `Transactional.flow`
  eos-commit-interval = 100ms

  # Size of buffer in element count
  buffer-size = 100

  # Strategy that is used when incoming elements cannot fit inside the buffer.
  # Possible values: "dropHead", "backpressure", "dropBuffer", "dropNew", "dropTail", "fail".
  overflow-strategy = "dropHead"

  # Properties defined by org.apache.kafka.clients.producer.ProducerConfig
  # can be defined in this configuration section.
  kafka-clients {
  }
}

Logging requests/responses of strict client HTTP calls with ConfiguredAhcWSClient

Unfortunately out-of-the-box Lagom doesn't support request/response logging for client strict HTTP calls. ConfiguredAhcWSClient is a simple custom implementation of the play.api.libs.ws.WSClient which Lagom uses to perform the strict client HTTP calls. It allows you to enable request/response (including the body) logging. It can be enabled in your application.conf as follows:

configured-ahc-ws-client.logging.enabled = true

Enjoy!

How to use

All released artifacts are available in the Maven central repository. Just add a lagom-extensions to your service dependencies:

  • SBT
libraryDependencies += "org.taymyr.lagom" %% "lagom-extensions-java" % "X.Y.Z"
  • Maven
<dependency>
  <groupId>org.taymyr.lagom</groupId>
  <artifactId>lagom-extensions-java_${scala.binary.version}</artifactId>
  <version>X.Y.Z</version>
</dependency>

All snapshot artifacts are available in the Sonatype snapshots repository. This repository must be added in your build system.

  • SBT
resolvers ++= Resolver.sonatypeRepo("snapshots")
  • Maven
<repositories>
  <repository>
    <id>snapshots-repo</id>
    <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    <releases><enabled>false</enabled></releases>
    <snapshots><enabled>true</enabled></snapshots>
  </repository>
</repositories>

Contributions

Contributions are very welcome.

License

Copyright © 2018-2020 Digital Economy League (https://www.digitalleague.ru/).

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project 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.