Using Quarkus resolvers with AWS Amplify

Igor Khripunov
2 min readJan 15, 2021

TL;DR: Ops-y writeup on how to marry Quarkus to Amplify without starting a fire. No resolver code provided, only build and setup considerations.

I’ve recently came across AWS Amplify and I was impressed with its capability to develop things fast and do things for the developer. However that comes at a price of doing things in the Amplify Way. On the other hand I’ve got a need to use things we know in the team and leverage some pre-existing libraries. This considerations led me to Amplify’s GraphQL API with Quarkus resolver. Here’s a brief technical overview of how to have both things at the same time.

AWS Amplify

On this side of things you need to create a custom Java function and make it a resolver in your GraphQL schema (see https://docs.amplify.aws/cli/function and https://docs.amplify.aws/cli/graphql-transformer/function for details).

Create a function

amplify add function❯ Lambda function (serverless function)
? Provide an AWS Lambda function name: fizzbuzz
❯ Java

Add a resolver to the schema

...
type Query {
getFizzBuzz: [String!] @function(name: "fizzbuzz-${env}")
}
...

Now let’s move on to the function itself

Quarkus Lambda

And here we are limited by the Amplify Way to only use Gradle. It’s nice enough to provide us with HelloWorld example. If we just slap Quarkus Gradle build bits on top we’ll get the following:

plugins {
id 'java'
id 'io.quarkus'
}

java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

repositories {
mavenLocal()
mavenCentral()
}

dependencies {
implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
implementation (
"io.quarkus:quarkus-amazon-lambda",
)

testImplementation (
"io.quarkus:quarkus-test-amazon-lambda",
"io.quarkus:quarkus-junit5",
)
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
}

jar.baseName = 'latest_build'
task buildZip(type: Zip) {
from compileJava
from processResources
into('lib') {
from configurations.runtimeClasspath
}
archiveFileName = 'latest_build.zip'
}
build.dependsOn buildZip

And that leads us to

Quarkus bootstrap failed.
java.jang.ClassNotFoundException: io.quarkus.runner.ApplicationImpl
at ...

That got me thinking… Hey! Quarkus plugin packages a zip of its own so buildZip function is not only useless but harmful. Ok, so let’s build without it:

amplify function build
...
Building resources. This may take a few minutes...
2021-01-15T10:53:02.612Z - error: uncaughtException: ENOENT: no such file or directory, open '.../amplify/backend/function/fizzbuzz/build/distributions/latest_build.zip'

Ah, it doesn’t really build the file that is called latest_build nor it places it into build/distributions . Solving that would be just copying a built file as the last step of the build:

task copyDist {
doLast {
copy {
from file("$buildDir/function.zip")
into file("$buildDir/distributions")
rename {
filename -> filename.replace 'function', 'latest_build'
}
}
}
}
build.finalizedBy(copyDist)

This time amplify push would succeed. Now we are not limited to a basic Java. I’m pretty sure Native Image build would be as successful.

--

--