Skip to content
Merged
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
68 changes: 68 additions & 0 deletions samples/quarkus/pet-store/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Quarkus Native Pet store example

The [Quarkus framework](https://quarkus.io/) is compatible with Spring's annotations and makes it easy to use [GraalVM](https://www.graalvm.org/) to build application images into native binaries. Further, Micronaut includes builtin support for AWS Lambda.

This demo application shows how to use Quarkus to compile our standard pet store example, using Spring annotations, into a native binary with GraalVM and execute it in AWS Lambda. To run this demo, you will need to have [Maven](https://maven.apache.org/) installed as well as [Docker](https://www.docker.com/) to build GraalVM native image.

With all the pre-requisites installed including:

* JDK 8 or above
* Maven 3.5.x

You should be able to build a native image of the application by running mvn from the repository's root.

```bash
$ mvn clean install -Pnative
```

The output of the build is a deployable zip called `function.zip` in the `target` folder.

To run the lambda locally, you can utilize the SAM cli. This should start up the listeners in the `PetsController`, and you can test locally with your preferred http client.

```bash
sam local start-api -t sam.native.yaml
```

For example, to test the GET /pets endpoint via curl:
```bash
curl localhost:3000/pets
```

You should see JSON output of pets.

To deploy the application to AWS Lambda you can use the pre-configured `sam-native.yaml` file included in the repo. Using the AWS or SAM CLI, run the following commands:

```bash
sam deploy -g -t sam.native.yaml
```

You should see the stack deployed successfully:

```bash
Stack quarkus-sample-pet-store outputs:
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
OutputKey-Description OutputValue
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
PetStoreNativeApi - URL for application https://xxxxxxxxxx.execute-api.xx-xxxx-1.amazonaws.com/Prod/
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - quarkus-sample-pet-store in xx-xxxx-1

```

Make a test request to the API endpoint using curl or your preferred http client.

For example, to check the GET /pets endpoint via curl:
```bash
curl https://xxxxxxxxxx.execute-api.xx-xxxx-1.amazonaws.com/Prod/pets
```

Finally, there’s an environment variable that must be set for native GraalVM deployments. If you look at sam.native.yaml you’ll see this:

```bash
Environment:
Variables:
DISABLE_SIGNAL_HANDLERS: true
```

This environment variable resolves some incompatibilites between GraalVM and the Amazon Lambda Custom Runtime environment.
141 changes: 141 additions & 0 deletions samples/quarkus/pet-store/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.amazonaws.serverless.sample</groupId>
<artifactId>serverless-quarkus-example</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.parameters>true</maven.compiler.parameters>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus-plugin.version>1.0.1.Final</quarkus-plugin.version>
<quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>1.0.1.Final</quarkus.platform.version>
<surefire-plugin.version>2.22.1</surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-lambda-http</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-web</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemProperties>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemProperties>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
</systemProperties>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>zip-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>function</finalName>
<descriptors>
<descriptor>src/assembly/zip.xml</descriptor>
</descriptors>
<attach>false</attach>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
</project>
36 changes: 36 additions & 0 deletions samples/quarkus/pet-store/sam.native.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Serverless Quarkus HTTP - com.amazon.quarkus.demo::pet-store
Globals:
Api:
EndpointConfiguration: REGIONAL
BinaryMediaTypes:
- "*/*"

Resources:
PetStoreNativeFunction:
Type: AWS::Serverless::Function
Properties:
Handler: not.used.in.provided.runtime
Runtime: provided
CodeUri: target/function.zip
MemorySize: 128
Policies: AWSLambdaBasicExecutionRole
Tracing: Active
Timeout: 15
Environment:
Variables:
DISABLE_SIGNAL_HANDLERS: true
Events:
GetResource:
Type: Api
Properties:
Path: /{proxy+}
Method: any

Outputs:
PetStoreNativeApi:
Description: URL for application
Value: !Sub 'https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/'
Export:
Name: PetStoreNativeApi
17 changes: 17 additions & 0 deletions samples/quarkus/pet-store/src/assembly/zip.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>lambda-package</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<files>
<file>
<source>${project.build.directory}${file.separator}${artifactId}-${version}-runner</source>
<outputDirectory>/</outputDirectory>
<destName>bootstrap</destName>
<fileMode>755</fileMode>
</file>
</files>
</assembly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.amazonaws.serverless.sample.quarkus;

import com.amazonaws.serverless.sample.quarkus.model.Pet;
import com.amazonaws.serverless.sample.quarkus.model.PetData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;
import java.util.UUID;

@RestController
public class PetsController {

private PetData petData;

@Autowired
public PetsController(PetData data) {
petData = data;
}

@RequestMapping(path = "/pets", method = RequestMethod.POST)
public Pet createPet(@RequestBody Pet newPet) {
if (newPet.getName() == null || newPet.getBreed() == null) {
return null;
}

Pet dbPet = newPet;
dbPet.setId(UUID.randomUUID().toString());
return dbPet;
}

@RequestMapping(path = "/pets", method = RequestMethod.GET)
public Pet[] listPets(@RequestParam("limit") Optional<Integer> limit) {
int queryLimit = 10;
if (limit.isPresent()) {
queryLimit = limit.get();
}

Pet[] outputPets = new Pet[queryLimit];

for (int i = 0; i < queryLimit; i++) {
Pet newPet = new Pet();
newPet.setId(UUID.randomUUID().toString());
newPet.setName(petData.getRandomName());
newPet.setBreed(petData.getRandomBreed());
newPet.setDateOfBirth(petData.getRandomDoB());
outputPets[i] = newPet;
}

return outputPets;
}

@RequestMapping(path = "/pets/{petId}", method = RequestMethod.GET)
public Pet getPet(@RequestParam("petId") String petId) {
Pet newPet = new Pet();
newPet.setId(UUID.randomUUID().toString());
newPet.setBreed(petData.getRandomBreed());
newPet.setDateOfBirth(petData.getRandomDoB());
newPet.setName(petData.getRandomName());
return newPet;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.amazonaws.serverless.sample.quarkus.model;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.quarkus.runtime.annotations.RegisterForReflection;

import java.util.Date;

@RegisterForReflection
public class Pet {
private String id;
private String breed;
private String name;
private Date dateOfBirth;

@JsonProperty("petId")
public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getBreed() {
return breed;
}

public void setBreed(String breed) {
this.breed = breed;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@JsonFormat(pattern = "YYYY-mm-dd")
public Date getDateOfBirth() {
return dateOfBirth;
}

public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}

}
Loading