A base
AWSClientConfiguration
is provided which can be used as a base configuration class for
any configuration that needs to configure an AWS SDK client.
2 Release History
Improve this doc
micronaut-function-aws-api-proxy
modules supports both Payload format version v1 and v2. For functions of type
Application
, use the handler
ApiGatewayProxyRequestEventFunction
for
Payload format version 1.0
and
APIGatewayV2HTTPEventFunction
for 2.0.
micronaut-function-aws-api-proxy
modules supports application load balancer events. For functions of type
Application
, use the handler
ApplicationLoadBalancerFunction
New dependency to use
Micronaut Serialization with AWS Lambda Events
.
It
provides a custom serialization implementation for Lambda
.
micronaut-function-aws-api-proxy
no longer depends on
AWS Serverless Java container
. Most of the modules classes have been deleted or changed.
If you use
io.micronaut.function.aws.proxy.MicronautLambdaHandler
as your AWS Lambda handler, change it to
ApiGatewayProxyRequestEventFunction
for
Payload format version 1.0
or
APIGatewayV2HTTPEventFunction
for payload format 2.0.
The
@IntentHandler
annotation and the associated
AnnotatedRequestHandler
have been removed.
@IntentHandler
helped to implement automatically the method
canHandle
of an Alexa’s handler.
If you had code, such as
@IntentHandler("HelloWorldIntent")
, you need to implement
canHandle
method. For example:
@Override
public boolean canHandle(HandlerInput handlerInput) {
return handlerInput.matches(Predicates.intentName("HelloWorldIntent"));
== Micronaut Function Name
Property `micronaut.function.name` takes precedence over the function name present in the Lambda Context.
IntentHandler
[]
io.micronaut.function.aws.alexa.annotation
io.micronaut.aws.alexa.annotation
AnnotatedRequestHandler
[]
io.micronaut.function.aws.alexa.handlers
io.micronaut.aws.alexa.handlers
AlexaIntents
io.micronaut.function.aws.alexa
io.micronaut.aws.alexa.conf
When using AWS API Proxy, the new support for server side content negotiation may require changes to tests. For example
a test that makes a call such as:
String result = client.toBlocking().retrieve(
HttpRequest.GET("/test")
.accept("text/plain"), String)
If the server implementation does not declare the route as
@Produces("text/plain")
the request won’t match.
Amazon Corretto is an OpenJDK distribution that provides free, long-term support with no pay-gated features or restrictions on how it’s used in production. Corretto is used by thousands of Amazon workloads; for example, it’s the JDK used by the AWS Lambda java11 runtime, which provides insights Amazon uses to push improvements upstream.
When working with AWS SDK, you may need to provide a
com.amazonaws.auth.AWSCredentialsProvider
. To ease that this module provides a utility class:
EnvironmentAWSCredentialsProvider
For example the following snippet show how you may configure a S3 Client if you set two environment variables:
export AWS_ACCESS_KEY_ID=XXXX
export AWS_SECRET_KEY=YYYY
AmazonS3ClientBuilder amazonS3ClientBuilder = AmazonS3ClientBuilder.standard();
amazonS3ClientBuilder.setCredentials(new EnvironmentAWSCredentialsProvider(applicationContext.getEnvironment()));
AmazonS3 s3 = amazonS3ClientBuilder.build();
Read about
externalized Configuration with property sources
in Micronaut.
8 AWS SDK v2
Improve this doc
By default, the AWS SDK v2 will pull transitively both the Netty (async) and Apache HTTP (sync) clients. If you wish
to use a client based on the JVM’s lightweight
URLConnection
, you should configure it as explained below.
To use the
URLConnection
-based client, you should exclude the other clients from the classpath:
Maven
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<exclusions>
<exclusion>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</exclusion>
<exclusion>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>
Gradle
implementation "software.amazon.awssdk:s3", {
exclude group: "software.amazon.awssdk", module: "apache-client"
exclude group: "software.amazon.awssdk", module: "netty-nio-client"
implementation "software.amazon.awssdk:url-connection-client"
Then, you can configure it with the following configuration properties:
Table 1. Configuration Properties for
UrlConnectionClientConfiguration
If you don’t exclude the other clients from the classpath, you still can configure which one is used by setting the
following JVM system properties:
software.amazon.awssdk.http.urlconnection.UrlConnectionSdkHttpService
for the
URLConnection
based client.
software.amazon.awssdk.http.apache.ApacheSdkHttpService
for the Apache HTTP client (if in the classpath).
Amazon ECS container credentials, loaded from Amazon ECS if the environment variable
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
is set.
Instance profile credentials, used on Amazon EC2 instances, and delivered through the Amazon EC2 metadata service.
accessKeyId = "your_access_key_id_here"
secretKey = "your_secret_key_id_here"
sessionToken = "your_session_token_here"
accessKeyId = "your_access_key_id_here"
secretKey = "your_secret_key_id_here"
sessionToken = "your_session_token_here"
"accessKeyId": "your_access_key_id_here",
"secretKey": "your_secret_key_id_here",
"sessionToken": "your_session_token_here"
You can override the endpoint of an AWS Service by setting
aws.services.*.endpoint-override
, for example, during testing.
For example, for AWS SQS, you can set
aws.services.sqs.endpoint-override=https://localhost:1234
.
8.5 API Gateway Management API Client
Improve this doc
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apigatewaymanagementapi</artifactId>
</dependency>
software.amazon.awssdk.services.apigatewaymanagementapi.ApiGatewayManagementApiClientBuilder
software.amazon.awssdk.services.apigatewaymanagementapi.ApiGatewayManagementApiClient
.
software.amazon.awssdk.services.apigatewaymanagementapi.ApiGatewayManagementApiAsyncClientBuilder
software.amazon.awssdk.services.apigatewaymanagementapi.ApiGatewayManagementApiAsyncClient
.
The HTTP client, credentials and region will be configured as per described in the
SDK v2 documentation
.
8.6 S3
Improve this doc
Micronaut provides a high-level, uniform object storage API that works across the major cloud providers:
Micronaut Object Storage
.
To get started, select the
object-storage-aws
feature in
Micronaut Launch
, or add the following dependency:
<dependency>
<groupId>io.micronaut.objectstorage</groupId>
<artifactId>micronaut-object-storage-aws</artifactId>
</dependency>
The HTTP client, credentials and region will be configured as per described in the
SDK v2 documentation
.
Additionally, this service accepts the following configuration properties:
Table 1. Configuration Properties for
S3ConfigurationProperties
The HTTP client, credentials and region will be configured as per described in the
SDK v2 documentation
.
8.8 SES
Improve this doc
The HTTP client, credentials and region will be configured as per described in the
SDK v2 documentation
.
8.9 SNS
Improve this doc
The HTTP client, credentials and region will be configured as per described in the
SDK v2 documentation
.
8.10 SQS
Improve this doc
The HTTP client, credentials and region will be configured as per described in the
SDK v2 documentation
.
8.11 SSM
Improve this doc
The HTTP client, credentials and region will be configured as per described in the
SDK v2 documentation
.
8.12 Secrets Manager
Improve this doc
The HTTP client, credentials and region will be configured as per described in the
SDK v2 documentation
.
8.13 Service discovery
Improve this doc
The HTTP client, credentials and region will be configured as per described in the
SDK v2 documentation
.
8.14 CloudWatch logging
Improve this doc
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-aws-cloudwatch-logging</artifactId>
</dependency>
The HTTP client, credentials and region will be configured as per described in the
SDK v2 documentation
.
8.14.1 Set CloudWatch Logging
Improve this doc
By default, Micronaut application will try to create the group and stream for you using AWS client. To disable this behavior you have to set the
createGroupAndStream
flag to
false
inside your appender.
Default value for group name is your application name and for stream name is your hostname. If you want you can change them by setting value
groupName
for group name and
streamName
for stream name.
Table 1. Configurable CloudWatchLoggingAppender Appender Properties
Boolean
If flag is set to true the Micronaut application will try to create group and stream on the AWS
blackListLoggerName
empty
List of logger names that won’t be published
<configuration>
<appender name="CLOUDWATCH" class="io.micronaut.aws.cloudwatch.logging.CloudWatchLoggingAppender">
<!-- <blackListLoggerName>example.app.Application</blackListLoggerName> -->
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
<jsonFormatter class="io.micronaut.aws.cloudwatch.logging.CloudWatchJsonFormatter" />
</layout>
</encoder>
<!-- <groupName>customGroupName</groupName> -->
<!-- <streamName>customStreamName</streamName> -->
<!-- <createGroupAndStream>true</createGroupAndStream> -->
</appender>
<root level="INFO">
<appender-ref ref="CLOUDWATCH" />
</root>
</configuration>
You can customize your JsonLayout with additional parameters the are available on official docs of
Logback’s JsonLayout
.
The
CloudWatchLoggingAppender
supports blacklisting the loggers by specifying the logger name. That might come handy if you want to use
level=DEBUG
or
level=TRACE
for the root logger level.
8.14.3 OpenTelemetry and logging
Improve this doc
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-logback-mdc-1.0</artifactId>
<version>1.16.0-alpha</version>
<scope>runtime</scope>
</dependency>
Inside your
src/main/resources/logback.xml
you should add a new appender
io.opentelemetry.instrumentation.logback.v1_0.OpenTelemetryAppender
.
src/main/resources/logback.xml
<configuration>
<appender name="CLOUDWATCH" class="io.micronaut.aws.cloudwatch.logging.CloudWatchLoggingAppender">
<!-- <blackListLoggerName>example.app.Application</blackListLoggerName> -->
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
<jsonFormatter class="io.micronaut.aws.cloudwatch.logging.CloudWatchJsonFormatter" />
</layout>
</encoder>
<!-- <groupName>customGroupName</groupName> -->
<!-- <streamName>customStreamName</streamName> -->
<!-- <createGroupAndStream>true</createGroupAndStream> -->
</appender>
<appender name="OTEL" class="io.opentelemetry.instrumentation.logback.v1_0.OpenTelemetryAppender">
<appender-ref ref="CLOUDWATCH" />
</appender>
<root level="INFO">
<appender-ref ref="OTEL" />
</root>
</configuration>
8.14.4 Emergency Appender
Improve this doc
Since this appender is queuing up log messages and then writing them remotely, there are a number of situations which might result in log messages not getting remoted correctly. To address such scenarios you can configure the emergency appender to preserve those messages.
Inside your
src/main/resources/logback.xml
you should add a new appender, in the example it is
STDOUT
. Inside the
CloudWatchLoggingAppender
add
appender-ref
that points to the new crated appender.
src/main/resources/logback.xml
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<withJansi>true</withJansi>
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n</pattern>
</encoder>
</appender>
<appender name="CLOUDWATCH" class="io.micronaut.aws.cloudwatch.logging.CloudWatchLoggingAppender">
<appender-ref ref="STDOUT"/>
<!-- <blackListLoggerName>example.app.Application</blackListLoggerName> -->
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
<jsonFormatter class="io.micronaut.aws.cloudwatch.logging.CloudWatchJsonFormatter" />
</layout>
</encoder>
<!-- <groupName>customGroupName</groupName> -->
<!-- <streamName>customStreamName</streamName> -->
<!-- <createGroupAndStream>true</createGroupAndStream> -->
</appender>
<root level="INFO">
<appender-ref ref="CLOUDWATCH" />
</root>
</configuration>
8.14.5 Browsing the Logs
Improve this doc
For advanced configuration options that are not suitable to provide via
application.yml
, you can declare a
BeanCreatedEventListener
bean that listens for builder bean creations, and apply any further customisation there:
@Singleton
public class S3ClientBuilderListener implements BeanCreatedEventListener<S3ClientBuilder> {
@Override
public S3ClientBuilder onCreated(BeanCreatedEvent<S3ClientBuilder> event) {
S3ClientBuilder builder = event.getBean();
builder.overrideConfiguration(ClientOverrideConfiguration.builder().retryPolicy(RetryMode.LEGACY).build());
return builder;
8.16 Other services
Improve this doc
Since the list of services offered by AWS is huge, you can write your own client support and leverage the foundation
classes that support the services supported by Micronaut.
To do so, you would create a @Factory
class that would get injected some other beans to do its job.
For example, to create a client for AWS Rekognition:
@Factory
public class RekognitionClientFactory extends AwsClientFactory<RekognitionClientBuilder, RekognitionAsyncClientBuilder, RekognitionClient, RekognitionAsyncClient> {
* @param credentialsProvider The credentials provider
* @param regionProvider The region provider
* @param userAgentProvider User-Agent provider
* @param awsServiceConfiguration AWS Service Configuration
protected RekognitionClientFactory(AwsCredentialsProviderChain credentialsProvider,
AwsRegionProviderChain regionProvider,
@Nullable UserAgentProvider userAgentProvider,
@Nullable @Named(RekognitionClient.SERVICE_NAME) AWSServiceConfiguration awsServiceConfiguration) {
super(credentialsProvider, regionProvider, userAgentProvider, awsServiceConfiguration);
// Sync client
@Override
protected RekognitionClientBuilder createSyncBuilder() { // (1)
return RekognitionClient.builder();
@Override
@Singleton
public RekognitionClientBuilder syncBuilder(SdkHttpClient httpClient) { // (2)
return super.syncBuilder(httpClient);
@Override
@Bean(preDestroy = "close")
public RekognitionClient syncClient(RekognitionClientBuilder builder) { // (3)
return super.syncClient(builder);
// Async client
@Override
protected RekognitionAsyncClientBuilder createAsyncBuilder() { // (1)
return RekognitionAsyncClient.builder();
@Override
@Singleton
@Requires(beans = SdkAsyncHttpClient.class)
public RekognitionAsyncClientBuilder asyncBuilder(SdkAsyncHttpClient httpClient) { // (2)
return super.asyncBuilder(httpClient);
@Override
@Bean(preDestroy = "close")
@Requires(beans = SdkAsyncHttpClient.class)
public RekognitionAsyncClient asyncClient(RekognitionAsyncClientBuilder builder) { // (3)
return super.asyncClient(builder);
This method needs to be implemented so that the parent factory class knows how to create the builder. You may apply
additional customisations to the builder here.
This method gives a chance to register a BeanCreaterEventListener
over the builder, so that any builder can be
customised. Needs to be overridden to apply the @Singleton
annotation.
This method builds the client. Needs to be overridden to apply the @Bean
annotation.
You can use StageResolver and its implementations HttpRequestStageResolver or
APIGatewayProxyRequestEventStageResolver to resolve the stage name.
Moreover, you can use AmazonApiGatewayUtils to check whether a resolved host matches the above format.
To use this API add the following dependency
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-aws-apigateway</artifactId>
</dependency>
To deploy a Micronaut function to AWS Lambda you have to choose a AWS Lambda Runtime. For Micronaut functions, you select a Java 17 runtime or custom runtime. To deploy your Micronaut function as a GraalVM Native Image you need to select a custom runtime.
Table 1. AWS Lambda Runtimes
Application
GraalVM Native Image in a AWS Lambda Custom Runtime
micronaut-function-aws-api-proxy, micronaut-function-aws-custom-runtime
Serverless Function
Java 17
micronaut-function-aws
Serverless Function
GraalVM Native Image in a AWS Lambda Custom Runtime
micronaut-function-aws, micronaut-function-aws-custom-runtime
Micronaut CLI or Launch will include the necessary dependencies when you select the aws-lambda
feature or both aws-lambda
and graalvm
features.
10.5 Lambda Triggers
Improve this doc
AWS Lambda integrates with other AWS services to invoke functions. The Micronaut application type you select depends on the triggers you want to support. To respond to incoming HTTP requests (e.g. AWS Lambda Proxy integrations in API Gateway) you can choose either Application
or Serverless Function
. For other triggers, such as consuming events from a queue, or run on a schedule you will choose Serverless Function
.
On the one hand, if you need to support a single endpoint a Serverless Function
gives you a function with less code (which translates to a faster cold startup).
On the other hand, functions written as an application of type Application
allows you to code with a more familiar paradigm - Classes annotated with @Controller
. That it is possible because, through the micronaut-function-aws-api-proxy dependency, Micronaut integrates with the AWS Lambda Java Events project.
10.6 AWS Lambda Test
Improve this doc
To smooth the developer experience when you use the micronaut-function-aws-api-proxy
dependency, Micronaut AWS offers the micronaut-function-aws-api-proxy-test
dependency.
Add it as a developmentOnly
dependency so that it is used when you run the app locally:
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-function-aws-api-proxy-test</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-function-aws-api-proxy-test</artifactId>
<scope>test</scope>
</dependency>
Application
RequestHandler<APIGatewayProxyRequestEvent,APIGatewayProxyResponseEvent>
ApiGatewayProxyRequestEventFunction
Application
RequestHandler<APIGatewayV2HTTPEvent,APIGatewayV2HTTPResponse>
APIGatewayV2HTTPEventFunction
Application
RequestHandler<ApplicationLoadBalancerRequestEvent,ApplicationLoadBalancerResponseEvent>
ApplicationLoadBalancerFunction
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-function-aws-api-proxy</artifactId>
</dependency>
For Serverless Functions the decision to use one MicronautRequestHandler
or MicronautRequestStreamHandler
depends on how you want to handle the input and output types.
To resolve those classes you need to add the micronaut-function-aws
dependency to your build.
Supply Generic types with the input and Output
Class which extends MicronautRequestHandler
Raw streams
MicronautRequestStreamHandler
<dependency>
<groupId>io.micronaut.serde</groupId>
<artifactId>micronaut-serde-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-aws-lambda-events-serde</artifactId>
</dependency>
micronaut-aws-lambda-events-serde
provides an implementation of com.amazonaws.services.lambda.runtime.CustomPojoSerializer
which is loaded via SPI.
This CustomPojoSerialization
avoids your Micronaut function paying a double hit on performance when using a serialization library inside the Lambda function.
10.11 AfterExecutionEvent
Improve this doc
AWS Lambda runtime will reuse the instances of your handler classes but the Java Virtual Machine will be suspended between the invocation. Every call on a single instance of your handler will reuse the same application context. If you need to perform actions before the JVM gets suspended then you can create synchronous handler for AfterExecutionEvent
event which is published right before the execution of the method handleRequest
in MicronautRequestHandler
and MicronautRequestStreamHandler
is finished.
To subscribe to AfterExecutionEvent
create a @Singleton
class which implements ApplicationEventListener<AfterExecutionEvent>
. Learn more about Context Events.
AfterExecutionEvent
is not published by either ApplicationLoadBalancerFunction, ApiGatewayProxyRequestEventFunction or
APIGatewayV2HTTPEventFunction handlers.
Instances of Lambda functions are automatically added as request concurrency increases.
When a new instance handles its first request it has to start the JVM and load your code, this one time process is called a cold start. The request is then processed, and the instance stays alive to be reused for subsequent requests. Lambda instances can be replaced over time and there is no way to determine how long a Lambda instance will live for.
Lambda function executions have different phases (Initialization, Invocation…).
During the initialization phase:
The intialization phase has access to more CPU, because of that Micronaut starts the application context and eagerly inits singletons during the intialization of the handler class.
10.13 GraalVM and AWS Custom runtimes
Improve this doc
GraalVM is a universal virtual machine which allows to compile Java programs to native executables.
The introduction of AWS Lambda custom runtimes enables cold startup improvements for Java applications running in AWS Lambda.
Micronaut’s dependency micronaut-function-aws-custom-runtime eases the creation of AWS Lambda Custom runtime to execute a Micronaut function.
The main API you will interact with is AbstractMicronautLambdaRuntime. An abstract class which you can extend to create your custom runtime mainClass
. That class includes the necessary code to perform the Processing Tasks described in the Custom Runtime documentation.
For Lambda responding to HTTP triggers, Micronaut AWS ships with several implementations of AbstractMicronautLambdaRuntime:
micronaut {
nativeLambda {
lambdaRuntimeClassName = "io.micronaut.function.aws.runtime.APIGatewayV2HTTPEventMicronautLambdaRuntime"
or via the Maven Plugin:
mvn package -Dpackaging=native-image -Dexec.mainClass=io.micronaut.function.aws.runtime.APIGatewayV2HTTPEventMicronautLambdaRuntime
When you generate a project with Micronaut CLI or Micronaut Launch with aws-lambda
and graalvm
features, the output includes the necessary files to generate a ZIP file to distribute your functions as a GraalVM Native Image executed from a AWS Lambda custom runtime.
Micronaut Framework needs an HTTP client to poll the Lambda Runtime when you deploy as a native executable. Add the following dependency to satisfy this requirement.
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<withJansi>false</withJansi>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %X{AWSFunctionVersion} %X{AWS-XRAY-TRACE-ID} %-5p %c{1} - %m%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
<logger name="groovycalamari.bots.l337" level="TRACE"/>
</configuration>
Override MicronautRequestHandler populateMappingDiagnosticContextValues
or populateMappingDiagnosticContextWithXrayTraceId
methods to adjust the functionality to your needs.
10.15 Micronaut AWS Lambda Tutorials
Improve this doc
Serverless Function
Java 11
Deploy a Serverless Micronaut function to AWS Lambda Java 11 Runtime
Application
GraalVM Native Image in Custom Runtime
Deploy a Micronaut application as a GraalVM Native Image to AWS Lambda
Serverless Function
GraalVM Native Image in Custom Runtime
Deploy a Micronaut function as a GraalVM Native Image to AWS Lambda
Serverless Function
Java 11
Micronaut AWS Lambda and S3 Event
Serverless Function
Java 11
Micronaut AWS Lambda and a Cron Job
To test Lambda handlers with JUnit 5, use the MicronautLambdaTest
annotation which will configure a suitable ApplicationContext
for use in a Lambda environment. The following
dependency is needed:
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-function-aws-test</artifactId>
<scope>test</scope>
</dependency>
Testing subclasses of MicronautRequestHandler
or MicronautRequestStreamHandler
with this annotation requires
both a no-arg and a one-arg constructor, the latter being used to inject the test application context:
public class SampleRequestHandler extends MicronautRequestHandler<String, String> {
// Used in AWS
public SampleRequestHandler() {
// Used in tests
public SampleRequestHandler(ApplicationContext applicationContext) {
super(applicationContext);
@Override
public String execute(String input) {
return null;
Example usage:
import io.micronaut.context.ApplicationContext;
import io.micronaut.function.aws.test.annotation.MicronautLambdaTest;
import org.junit.jupiter.api.Test;
import jakarta.inject.Inject;
@MicronautLambdaTest
public class RequestHandlerTest {
@Inject
private ApplicationContext context;
@Test
void testHandler() {
SampleRequestHandler sampleRequestHandler = new SampleRequestHandler(context);
// ...
The annotation supports the same options as @MicronautTest
. Please note that regardless of whether or not you provide
a custom builder, some Lambda-specific configuration will be set (e.g. eager initialization and active environments).
10.17 MicronautRequestStreamHandler
Improve this doc
Use MicronautRequestStreamHandler in combination of a class annotated with @FunctionBean which implements one of the interfaces from the java.util.function
package.
Table 1. Functional Interfaces
import io.micronaut.function.FunctionBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.function.Consumer;
@FunctionBean("eventlogger")
public class EventLogger implements Consumer<String> {
private static final Logger LOG = LoggerFactory.getLogger(EventLogger.class);
@Override
public void accept(String input) {
LOG.info("Received: {}", input);
import groovy.transform.CompileStatic
import io.micronaut.function.FunctionBean
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.util.function.Consumer
@CompileStatic
@FunctionBean('eventlogger')
class EventLogger implements Consumer<String> {
private static final Logger LOG = LoggerFactory.getLogger(EventLogger.class)
@Override
void accept(String input) {
LOG.info("Received: {}", input)
import io.micronaut.function.FunctionBean
import org.slf4j.LoggerFactory
import java.util.function.Consumer
@FunctionBean("eventlogger")
class EventLogger : Consumer<String> {
override fun accept(input: String) {
LOG.info("Received: {}", input)
companion object {
private val LOG = LoggerFactory.getLogger(EventLogger::class.java)
A single project can define multiple functions, however only a single function should be configured for execution by the application.
By default, it is resolved via the property micronaut.function.name
. If not present, the function name present in the Lambda Context, the name of the function on the AWS Console, is used.
Alternatively, you can write a custom Handler which extends MicronautRequestStreamHandler and overrides MicronautRequestStreamHandler::resolveFunctionName(Environment)
import io.micronaut.context.env.Environment;
import io.micronaut.core.annotation.Introspected;
import io.micronaut.function.aws.MicronautRequestStreamHandler;
@Introspected
public class Handler extends MicronautRequestStreamHandler {
@Override
protected String resolveFunctionName(Environment env) {
return "eventlogger";
import io.micronaut.context.env.Environment
import io.micronaut.core.annotation.Introspected
import io.micronaut.function.aws.MicronautRequestStreamHandler
@Introspected
class Handler extends MicronautRequestStreamHandler {
@Override
protected String resolveFunctionName(Environment env) {
'eventlogger'
import io.micronaut.context.env.Environment
import io.micronaut.function.aws.MicronautRequestStreamHandler
class Handler : MicronautRequestStreamHandler() {
override fun resolveFunctionName(env: Environment): String {
return "eventlogger"
10.18 Invoke Lambda with @FunctionClient
Improve this doc
Micronaut AWS provides support for invoking AWS Lambda functions within a Micronaut application context.
To use the features described in this section, you will need to have the micronaut-function-client-aws
dependency on your classpath.
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-function-client-aws</artifactId>
</dependency>
You can define multiple named functions under the aws.lambda.functions
configuration.
Each is configured by AWSInvokeRequestDefinition
that allows setting any property on the underlying com.amazonaws.services.lambda.model.InvokeRequest
.
For example, you invoke a function named AwsLambdaFunctionName
, in the AWS Lambda console, with the following configuration:
import io.micronaut.function.client.FunctionClient;
import jakarta.inject.Named;
@FunctionClient
public interface AnalyticsClient {
@Named("analytics") // (1)
String visit(String productId);
import io.micronaut.function.client.FunctionClient;
import jakarta.inject.Named;
@FunctionClient
interface AnalyticsClient {
@Named('analytics') // (1)
String visit(String productId);
internal interface AnalyticsClient {
@Named("analytics")
fun visit(productId: String): String
@FunctionClient
internal interface AnalyticsClient {
fun analytics(productId: String): String
To configure credentials for invoking the function you can either define a ~/.aws/credentials
file or use the application configuration file. Micronaut registers a EnvironmentAWSCredentialsProvider that resolves AWS credentials from the Micronaut Environment.
To create the sample skill described in
Amazon Documentation - Develop your first skill with Micronaut’s Alexa you will write the same LaunchRequestHandler, HelloWorldIntent, HelpIntent, CancelandStopHandler, FallbackIntentHandler, SessionEndedRequestHandler handlers.
You will do just one change, you will annotate those handlers with jakarta.inject.Singleton
.
import com.amazon.ask.dispatcher.request.handler.HandlerInput;
import com.amazon.ask.dispatcher.request.handler.RequestHandler;
import com.amazon.ask.model.Response;
import com.amazon.ask.request.Predicates;
import jakarta.inject.Singleton;
import java.util.Optional;
@Singleton (1)
public class HelloWorldIntentHandler implements RequestHandler {
@Override
public boolean canHandle(HandlerInput input) {
return input.matches(Predicates.intentName("HelloWorldIntent"));
@Override
public Optional<Response> handle(HandlerInput input) {
String speechText = "Hello world";
return input.getResponseBuilder()
.withSpeech(speechText)
.withSimpleCard("HelloWorld", speechText)
.build();
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-function-aws-alexa</artifactId>
</dependency>
As handler specify io.micronaut.function.aws.alexa.AlexaFunction
. You don’t need to create a class which extends SkillStreamHandler
, AlexaFunction takes care of adding request handlers interceptors etc.
11.5 Alexa Skill as a Web Service
Improve this doc
The micronaut-aws-webservice
is a fork of Amazon Servlet module. It allow you to run your Alexa Skill backend logic in Micronaut applications deployed with a netty or servlet runtimes.
Just by including the dependency:
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-aws-alexa-httpserver</artifactId>
</dependency>
You can configure your Skill’s endpoint under Build/Endpoint
in the Alexa developer console.
11.6 SSML Builder
Improve this doc
package io.micronaut.aws.alexa.flashbriefing;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import jakarta.validation.Validator;
import java.util.List;
import java.util.stream.Collectors;
@Controller("/news")
public class FlashBriefingsController {
private final Validator validator;
private final FlashBriefingRepository flashBriefingRepository;
public FlashBriefingsController(Validator validator,
FlashBriefingRepository flashBriefingRepository) {
this.validator = validator;
this.flashBriefingRepository = flashBriefingRepository;
@Get // (1)
public List<FlashBriefingItem> index() {
return flashBriefingRepository.find()
.stream()
.filter(item -> validator.validate(item).isEmpty()) // (2)
.sorted() // (3)
.limit(5) // (4)
.collect(Collectors.toList());
By default, Micronaut sets the response HTTP Header Content-Type
with the value application-json
.
Flash Briefing Feed items must be valid according to Flash Briefing Skill API Feed Reference constraints.
Items should be provided in order from newest to oldest, based on the date value for the item. Alexa may ignore older items.
Flash Briefing Skill API Feed Reference instructs to provide between 1 and 5 unique items at a time.
If the built-in methods do not meet your use case, create a bean of type HandlerInputLocaleResolver and set its order (through the getOrder
method) relative to the existing resolvers.
12 Distributed Configuration
Improve this doc
Micronaut AWS supports distributed configuration via services such as AWS Secrets Manager and AWS System Manager Parameter Store.
You can create environment-specific configurations as well by including the environment name after an underscore _
. For example if micronaut.application.name
is set to helloworld
, specifying configuration values under helloworld_test
will be applied only to the test
environment.
Note the trailing slash in the configuration names.
Table 1. Configuration Resolution Precedence
/config/[APPLICATION_NAME]/
Application-specific configuration, example /config/hello-world
🔝🔝🔝
/config/application_prod/
Configuration shared by all applications for the prod
Environment
🔝🔝🔝🔝
/config/[APPLICATION_NAME]_prod/
Application-specific configuration for an active Environment
For example, if the configuration name /config/application_test/server.url
is configured in AWS Parameter Store, any application connecting to that parameter store can retrieve the value using server.url
. If the application has micronaut.application.name
configured to be myapp
, a value with the name /config/myapp_test/server.url
overrides the value just for that application.
Table 2. Configuration Properties for AwsDistributedConfigurationProperties
aws.distributed-configuration.delimiter
java.lang.String
Delimiter for AWS Distributed Configuration resources names. Default value ("/").
aws.distributed-configuration.search-active-environments
boolean
Search additional paths suffixed with each active environment. e.g. /config/application_ec2 Default value (true).
aws.distributed-configuration.search-common-application
boolean
Whether paths for the Default Application name should be searched or not. Default value (true).
aws.distributed-configuration.prefixes
java.util.List
List of prefixes for AWS Distributed Configuration resources names. If it is non-empty, {@link AwsDistributedConfiguration#getPrefix()} is not used.
aws.distributed-configuration.prefix
java.lang.String
Prefix for AWS Distributed Configuration resources names. Default ("/config/")
aws.distributed-configuration.common-application-name
java.lang.String
Default Application name. Default value ("application").
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-aws-secretsmanager</artifactId>
</dependency>
To enable distributed configuration, create a src/main/resources/bootstrap.yml
file and enable the configuration client:
src/main/resources/bootstrap.yml
micronaut:
config-client:
enabled: true
Example:
If you add micronaut.application.name: myapp
to bootstrap.yml
and you start your app in the dev
Micronaut environment the secret shown in the following image is read and two properties micronaut.security.oauth2.clients.companyauthserver.client-id
and micronaut.security.oauth2.clients.companyauthserver.client-secret
are exposed to your application:
To avoid secret keys naming collision in the Micronaut application context, which is caused by the strict naming convention specified by some AWS services, add a configuration section to src/main/resources/bootstrap.yml
.
For example, if you would like to use multiple RDS instances, you can do it in the following way:
src/main/resources/bootstrap.yml
micronaut:
config-client:
enabled: true
secretsmanager:
secrets:
- secret-name: rds
prefix: datasources.default
- secret-name: rds_backup
prefix: datasources.backup
Note that secret-name
is a name suffix of the secret configured in AWS Secret Manager. For example, to add rds_backup
configuration for a production
environment, add the rds_backup
configuration entry to the src/main/resources/bootstrap.yml
as shown in the example above. Also, create RDS secret in AWS Secret Manager with name /config/application_prod/rds_backup
or /config/[APPLICATION_NAME]_prod/rds_backup
.
Note that prefix
is a unique key prefix that is prepended to all keys that belong to a given secret.
To learn more about the Micronaut environments, go to Environments
12.2 Prefixes used for searching secrets
Improve this doc
aws {
distributedConfiguration = "search-active-environments:false search-common-application:false"
aws {
distributed-configuration = "search-active-environments:false search-common-application:false"
"aws": {
"distributed-configuration": "search-active-environments:false search-common-application:false"
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-aws-parameter-store</artifactId>
</dependency>
To enable distributed configuration a src/main/resources/bootstrap.yml
configuration file must be created and configured to use Parameter Store:
bootstrap.yml
micronaut:
application:
name: hello-world
config-client:
enabled: true
client:
system-manager:
parameterstore:
enabled: true
See the configuration reference for all configuration options.
You can configure shared properties from the AWS Console → System Manager → Parameter Store.
Micronaut uses a hierarchy to read configuration values, and supports String
, StringList
, and SecureString
types.
Each level of the tree can be composed of key=value pairs. For multiple key/value pairs, set the type to StringList
.
For special secure information, such as keys or passwords, use the type SecureString
. KMS will be automatically invoked when you add and retrieve values, and will decrypt them with the default key store for your account. If you set the configuration to not use secure strings, they will be returned to you encrypted and you must manually decrypt them.
13 Repository
Improve this doc