Micronaut AWS

Provides integration between Micronaut and Amazon Web Services (AWS)

Version:

1 Introduction

This project provides various extensions to Micronaut for Amazon Web Services (AWS).

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

For this project, you can find a list of releases (with release notes) here:

https://github.com/{githubSlug}/releases[https://github.com/{githubSlug}/releases]

3 What's new?

Micronaut AWS 2.0.0 contains improvements to ease the creation of Alexa Skills with Micronaut:

  • Support for AWS SDK v2.

  • Improvements to GraalVM support on Lambda.

  • Creation of Alexa Skills as http services.

  • Creation of Flash Briefing skills.

  • Easier creation of SSML.

Check the Alexa section to learn more.

See the section Breaking Changes to ease into the migration to Micronaut AWS 2.x

4 Amazon Correto

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.

5 AWS SDK v1

To use the AWS SDK v1, add the following dependency:

implementation("io.micronaut.aws:micronaut-aws-sdk-v1")
<dependency>
    <groupId>io.micronaut.aws</groupId>
    <artifactId>micronaut-aws-sdk-v1</artifactId>
</dependency>

5.1 AWS Credentials Provider

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();

6 AWS SDK v2

To use the AWS SDK v2, add the following dependency:

implementation("io.micronaut.aws:micronaut-aws-sdk-v2")
<dependency>
    <groupId>io.micronaut.aws</groupId>
    <artifactId>micronaut-aws-sdk-v2</artifactId>
</dependency>

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.

URLConnection client

To use the URLCnnection-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
Property Type Description

aws.url-connection-client.socket-timeout

java.time.Duration

aws.url-connection-client.connection-timeout

java.time.Duration

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.service.impl. Possible values:

    • 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).

  • software.amazon.awssdk.http.async.service.impl. Possible values:

    • software.amazon.awssdk.http.nio.netty.NettySdkAsyncHttpService for the Netty client (if in the classpath).

Apache HTTP client

The Apache HTTP client can be configured with the following options:

🔗
Table 2. Configuration Properties for ApacheClientConfiguration
Property Type Description

aws.apache-client.socket-timeout

java.time.Duration

aws.apache-client.connection-timeout

java.time.Duration

aws.apache-client.connection-acquisition-timeout

java.time.Duration

aws.apache-client.max-connections

java.lang.Integer

aws.apache-client.local-address

java.net.InetAddress

aws.apache-client.expect-continue-enabled

java.lang.Boolean

aws.apache-client.connection-time-to-live

java.time.Duration

aws.apache-client.connection-max-idle-time

java.time.Duration

aws.apache-client.use-idle-connection-reaper

java.lang.Boolean

aws.apache-client.proxy.endpoint

java.net.URI

aws.apache-client.proxy.username

java.lang.String

aws.apache-client.proxy.password

java.lang.String

aws.apache-client.proxy.ntlm-domain

java.lang.String

aws.apache-client.proxy.ntlm-workstation

java.lang.String

aws.apache-client.proxy.non-proxy-hosts

java.util.Set

aws.apache-client.proxy.add-non-proxy-host

java.lang.String

aws.apache-client.proxy.preemptive-basic-authentication-enabled

java.lang.Boolean

aws.apache-client.proxy.use-system-property-values

java.lang.Boolean

Netty client

The Netty client can be configured with the following options:

🔗
Table 3. Configuration Properties for NettyClientConfiguration
Property Type Description

aws.netty-client.max-concurrency

java.lang.Integer

aws.netty-client.max-pending-connection-acquires

java.lang.Integer

aws.netty-client.read-timeout

java.time.Duration

aws.netty-client.write-timeout

java.time.Duration

aws.netty-client.connection-timeout

java.time.Duration

aws.netty-client.connection-acquisition-timeout

java.time.Duration

aws.netty-client.connection-time-to-live

java.time.Duration

aws.netty-client.connection-max-idle-time

java.time.Duration

aws.netty-client.use-idle-connection-reaper

java.lang.Boolean

aws.netty-client.protocol

software.amazon.awssdk.http.Protocol

aws.netty-client.max-http2streams

java.lang.Integer

aws.netty-client.proxy.host

java.lang.String

aws.netty-client.proxy.port

int

aws.netty-client.proxy.scheme

java.lang.String

aws.netty-client.proxy.non-proxy-hosts

java.util.Set

Supplying AWS credentials

By default, AWS SDK v2 will attempt to find AWS credentials from the following places:

  1. Java system properties: aws.accessKeyId and aws.secretAccessKey.

  2. Environment variables: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

  3. The default credential profiles file: ~/.aws/credentials.

  4. Amazon ECS container credentials, loaded from Amazon ECS if the environment variable AWS_CONTAINER_CREDENTIALS_RELATIVE_URI is set.

  5. Instance profile credentials, used on Amazon EC2 instances, and delivered through the Amazon EC2 metadata service.

For more information, check the AWS documentation.

If you still want to specify the credentials via configuration, you can do so in application.yml:

aws:
  accessKeyId: your_access_key_id_here
  secretKey: your_secret_key_id_here
  sessionToken: your_session_token_here

AWS region selection

By default, AWS SDK v2 will attempt to determine the AWS region in the following ways:

  1. Environment variable: AWS_REGION.

  2. The default shared configuration file: ~/.aws/config.

  3. Amazon EC2 instance metadata service.

For more information, check the AWS documentation.

If you still want to specify the region via configuration, you can do so in application.yml:

aws:
  region: eu-west-1

Third-party libraries

If you are looking for a higher-level API, check out Agorapulse’s AWS SDK for Micronaut.

6.1 S3

To use an S3 client, add the following dependency:

implementation("software.amazon.awssdk:s3")
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
</dependency>

Then, the following beans will be created:

  • software.amazon.awssdk.services.s3.S3ClientBuilder

  • software.amazon.awssdk.services.s3.S3Client.

And:

  • software.amazon.awssdk.services.s3.S3AsyncClientBuilder

  • software.amazon.awssdk.services.s3.S3AsyncClient.

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
Property Type Description

aws.s3.dualstack-enabled

java.lang.Boolean

aws.s3.accelerate-mode-enabled

java.lang.Boolean

aws.s3.path-style-access-enabled

java.lang.Boolean

aws.s3.checksum-validation-enabled

java.lang.Boolean

aws.s3.chunked-encoding-enabled

java.lang.Boolean

aws.s3.use-arn-region-enabled

java.lang.Boolean

aws.s3.profile-name

java.lang.String

6.2 Dynamo DB

To use a DynamoDb client, add the following dependency:

implementation("software.amazon.awssdk:dynamodb")
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>dynamodb</artifactId>
</dependency>

Then, the following beans will be created:

  • software.amazon.awssdk.services.dynamodb.DynamoDbClientBuilder

  • software.amazon.awssdk.services.dynamodb.DynamoDbClient.

And:

  • software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClientBuilder

  • software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient.

The HTTP client, credentials and region will be configured as per described in the SDK v2 documentation.

6.3 SES

To use a SES client, add the following dependency:

implementation("software.amazon.awssdk:ses")
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>ses</artifactId>
</dependency>

Then, the following beans will be created:

  • software.amazon.awssdk.services.ses.SesClientBuilder

  • software.amazon.awssdk.services.ses.SesClient.

And:

  • software.amazon.awssdk.services.ses.SesAsyncClientBuilder

  • software.amazon.awssdk.services.ses.SesAsyncClient.

The HTTP client, credentials and region will be configured as per described in the SDK v2 documentation.

6.4 SNS

To use a SNS client, add the following dependency:

implementation("software.amazon.awssdk:sns")
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>sns</artifactId>
</dependency>

Then, the following beans will be created:

  • software.amazon.awssdk.services.sns.SnsClientBuilder

  • software.amazon.awssdk.services.sns.SnsClient.

And:

  • software.amazon.awssdk.services.sns.SnsAsyncClientBuilder

  • software.amazon.awssdk.services.sns.SnsAsyncClient.

The HTTP client, credentials and region will be configured as per described in the SDK v2 documentation.

6.5 SQS

To use a SQS client, add the following dependency:

implementation("software.amazon.awssdk:sqs")
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>sqs</artifactId>
</dependency>

Then, the following beans will be created:

  • software.amazon.awssdk.services.sqs.SqsClientBuilder

  • software.amazon.awssdk.services.sqs.SqsClient.

And:

  • software.amazon.awssdk.services.sqs.SqsAsyncClientBuilder

  • software.amazon.awssdk.services.sqs.SqsAsyncClient.

The HTTP client, credentials and region will be configured as per described in the SDK v2 documentation.

6.6 Advanced configuration

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;
    }
}

6.7 Other services

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> {

    protected RekognitionClientFactory(AwsCredentialsProviderChain credentialsProvider, AwsRegionProviderChain regionProvider) {
        super(credentialsProvider, regionProvider);
    }

    // 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);
    }
}
1 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.
2 This method gives a chance to register a BeanCreaterEventListener over the builder, so that any builder can be customised. Needs to be overriden to apply the @Singleton annotation.
3 This method builds the client. Needs to be overriden to apply the @Bean annotation.

7 AWS Lambda Support

There are several ways to create Micronaut AWS Lambda functions.

7.1 Micronaut Application Types for AWS Lambda

In Micronaut Launch, you can select the feature aws-lambda for applications of type Application or Serverless Function. Those application types have their CLI equivalents commands.

Application Type CLI Command

Application

create-app

Serverless Function

create-function-app

7.2 AWS Lambda Considerations

To deploy a AWS Lambda function you have to:

  • Select a runtime

  • Choose how your Lambda is triggered

  • Specify your Handler

  • Upload your code

The above decisions influence the type of Micronaut application you choose.

7.3 AWS Lambda Runtimes

To deploy a Micronaut function to AWS Lambda you have to choose a AWS Lambda Runtime. For Micronaut functions, you select a Java (8 or 11) or custom runtime. To deploy your Micronaut function as a GraalVM Native Image you need to select a custom runtime.

Select Java 11 Corretto Runtime
Select Custom Runtime

7.4 Application Types, Lambda Runtimes, Dependencies

Depending on your application type and runtime, you need different dependencies:

Application Type AWS Lambda Runtime ArtifactId

Application

Java 8/11

micronaut-function-aws-api-proxy

Application

GraalVM Native Image in a AWS Lambda Custom Runtime

micronaut-function-aws-api-proxy, micronaut-function-aws-custom-runtime

Serverless Function

Java 8/ 11

micronaut-function-aws

Serverless Function

GraalVM Native Image in a AWS Lambda Custom Runtime

micronaut-function-aws, micronaut-function-aws-custom-runtime

The previous set of artifacts have a group id of io.micronaut.aws.

Micronaut CLI or Launch will include the necessary dependencies when you select the aws-lambda feature or both aws-lambda and graalvm features.

7.5 Lambda Triggers

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.

Application Type Trigger type

Application or Serverless Function

HTTP requests to a single endpoint

Application

HTTP requests to multiple endpoints

Serverless Function

S3 events, events for a queue, schedule triggers etc.

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 Serverless Java Container project.

7.6 Lambda Handlers

Your Lambda function’s handler is the method in your function code that processes events. When your function is invoked, Lambda runs the handler method. When the handler exits or returns a response, it becomes available to handle another event.

The aws-lambda-java-core library defines two interfaces for handler methods. When coding your functions with Micronaut you don’t implement those interfaces directly. Instead you extend or use its Micronaut equivalents:

Application Type AWS Handler Interface Micronaut Handler Class

Serverless Function

com.amazonaws.services.lambda.runtime.RequestHandler

MicronautRequestHandler

Serverless Function

com.amazonaws.services.lambda.runtime.RequestStreamHandler

MicronautRequestStreamHandler

Application

RequestStreamHandler<AwsProxyRequest,AwsProxyResponse>

MicronautLambdaHandler

For functions of type Application, use the handler MicronautLambdaHandler.

To resolve that class you need to add the micronaut-function-aws-api-proxy dependency to your build.

implementation("io.micronaut:micronaut-function-aws-api-proxy")
<dependency>
    <groupId>io.micronaut</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.

implementation("io.micronaut:micronaut-function-aws")
<dependency>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-function-aws</artifactId>
</dependency>

With MicronautRequestHandler, it is expected that you supply generic types with the input and the output types. If you wish to work with raw streams then subclass MicronautRequestStreamHandler instead.

Input / Output Types Handler

Supply Generic types with the input and Output

Class which extends MicronautRequestHandler

Raw streams

MicronautRequestStreamHandler

7.7 Cold Startups

Instances of Lambdas are added and removed dynamically. When a new instance handles its first request, the response time increases, which is called a cold start. After that request is processed, the instance stays alive (≈10 m) to be reused for subsequent requests.

Lambdas execution have different phases (Initialization, Invocation…​).

During the initialization phase:

  • AWS Lambda starts a JVM.

  • Java runtime loads and initializes handler class.

  • Lambda calls the handler method.

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.

7.8 GraalVM and AWS Custom runtimes

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.

A runtime is a program that runs a Lambda function’s handler method when the function is invoked. You can include a runtime in your function’s deployment package in the form of an executable file named bootstrap

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.

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.

7.9 Micronaut AWS Lambda Tutorials

Check the step-by-step tutorials to get you started:

Application Type Runtime Tutorial

Application

Java 11

Deploy a Micronaut application to AWS Lambda Java 11 Runtime JAVA KOTLIN GROOVY

Serverless Function

Java 11

Deploy a Serverless Micronaut function to AWS Lambda Java 11 Runtime JAVA KOTLIN GROOVY

Application

GraalVM Native Image in Custom Runtime

Deploy a Micronaut application as a GraalVM Native Image to AWS Lambda JAVA KOTLIN

Serverless Function

GraalVM Native Image in Custom Runtime

Deploy a Serverless Micronaut function as a GraalVM Native Image to AWS Lambda JAVA

8 Alexa Support

The Micronaut’s aws-alexa module simplifies development of Alexa Skills with Java, Kotlin or Groovy.

implementation("io.micronaut.aws:micronaut-aws-alexa")
<dependency>
    <groupId>io.micronaut.aws</groupId>
    <artifactId>micronaut-aws-alexa</artifactId>
</dependency>

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 javax.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 javax.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();
    }

}
1 The Singleton scope indicates only one instance of the bean should exist in the Micronaut’s Bean Context

Typically, the next step will be to provide an instance of AlexaSkillConfiguration. The easiest way to do that is to configure the skill id via configuration:

alexa:
  skills:
    myskill:
      skill-id 'xxxx-yaaa-zz123'

Micronaut’s alexa module provides by default StandardSkillBuilderProvider which creates an SDK instance using the Skills.standard builder. You can provide your own implementation of Micronaut’s SkillBuilderProvider.

For each AlexaSkillConfiguration bean, Micronaut uses the builder provided by [SkillBuilderProvider to create for you a bean of type AlexaSkill for you and wires up the beans of the following types:

  • com.amazon.ask.dispatcher.request.handler.RequestHandler

  • com.amazon.ask.dispatcher.request.interceptor.RequestInterceptor

  • com.amazon.ask.dispatcher.request.interceptor.ResponseInterceptor

  • com.amazon.ask.dispatcher.exception.ExceptionHandler

  • com.amazon.ask.builder.SkillBuilder

8.1 SSML Builder

Micronaut Alexa ships with a Speech Systhesys Markup Language builder.

new Ssml().speak(new Ssml("Welcome to Ride Hailer. ").audio('soundbank://soundlibrary/transportation/amzn_sfx_car_accelerate_01').build()).build() == '<speak>Welcome to Ride Hailer. <audio src="soundbank://soundlibrary/transportation/amzn_sfx_car_accelerate_01"/></speak>'

8.2 The IntentHandler Annotation

To simplify the programming model Micronaut AWS includes a @IntentHandler annotation that can be used on any bean method to make the method an intent handler.

The method must accept a single value of type com.amazon.ask.dispatcher.request.handler.HandlerInput and return a value of type Optional<com.amazon.ask.model.Response> otherwise a compilation error will occur.

A typical Alexa application written in Micronaut looks like:

1 The javax.inject.Singleton annotation is used to define AlexApplication as a bean
2 Other services can be dependency injected into the constructor
3 The @IntentHandler is used to indicate which methods are intent handlers
4 The method receives a HandlerInput and returns a Response

8.3 Alexa Skill as a Web Service

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:

implementation("io.micronaut.aws:micronaut-aws-alexa-httpserver")
<dependency>
    <groupId>io.micronaut.aws</groupId>
    <artifactId>micronaut-aws-alexa-httpserver</artifactId>
</dependency>

you get an POST endpoint at /alexa (the route is configurable via alexa.endpoint.path.

You can configure your Skill’s endpoint under Build/Endpoint in the Alexa developer console.

8.4 Alexa Skill as an AWS Lambda Function

The micronaut-function-aws-alexa module includes support for building deploying an Alexa Skill as a Lambda Function.

implementation("io.micronaut.aws:micronaut-function-aws-alexa")
<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.

8.5 Flash Briefings

Micronaut’s eases the creation of Flash Briefing Skills.

You can create a flash briefing skill to provide Alexa customers with news headlines and other short content. Typically a flash briefing becomes a part of a customer’s daily routine.

Your application must expose an endpoint which returns a JSON Array of FlashBriefingItem

package io.micronaut.aws.alexa.flashbriefing;

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

import javax.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());
    }

}
1 By default, Micronaut sets the response HTTP Header Content-Type with the value application-json.
2 Flash Briefing Feed items must be valid according to Flash Briefing Skill API Feed Reference constraints.
3 Items should be provided in order from newest to oldest, based on the date value for the item. Alexa may ignore older items.
4 Flash Briefing Skill API Feed Reference instructs to provide between 1 and 5 unique items at a time.

9 Repository

You can find the source code of this project in this repository:

10 Breaking Changes

Class changes

AlexaFunction has been refactored to ease extension.

Table 1. Classes renamed
Old Class Name New Class

io.micronaut.function.aws.alexa.AlexaConfiguration

io.micronaut.aws.alexa.conf.AlexaSkillConfiguration

Table 2. Classes relocated
Class Name Old Package New Package

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

Artifact changes

Now all artifacts are published under the io.micronaut.aws group id.

Table 3. Artifacts relocated
Old artifact New artifact

io.micronaut:micronaut-function-aws

io.micronaut.aws:micronaut-function-aws

Content negotiation

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.