Search code examples
amazon-web-servicesaws-lambdaaws-api-gatewaymicronaut

How to create a CRUD API on Amazon Lambda using Micronaut


I want to create a CRUD API using Micronaut and deploy it on AWS Lambda, exposing the different methods with Amazon API Gateway. I could create different Kotlin Projects per endpoint (GET, POST...), one including one function, but that's kind of cumbersome so I'd rather have a single project with all the CRUD functions.

My current application contains two functions: one Supplier (GET) and one Consumer (POST).

Application:

object Application {
        @JvmStatic
        fun main(args: Array<String>) {
            Micronaut.build()
                    .packages("micronaut.aws.poc")
                    .mainClass(Application.javaClass)
                    .start()
        }
}

Supplier:

@FunctionBean("micronaut-aws-poc")
class MicronautAwsPocFunction : Supplier<String> {

    override fun get(): String {
        println("GET")
        return "micronaut-aws-poc"
    }
}

Consumer:

@FunctionBean("micronaut-aws-poc-post")
class MicronautAwsPocPostFunction : Consumer<String> {

    override fun accept(t: String) {
        println("POST $t")
    }

}

Then, I have created a resource in Amazon API Gateway with one GET and one POST method. The problem is, no matter which one I call, the MicronautAwsPocFunction is always invoked.

  1. Is it possible/recommended to embed many functions in a single jar?
  2. How can I make POST invocations call the MicronautAwsPocPostFunction instead of the MicronautAwsPocFunction?
  3. In case I wanted an additional PUT function, how could I model it?

Solution

  • I tried a different approach, this is how I solved it:

    Instead of using functions I changed to Lambda Functions Using AWS API Gateway Proxy. Also take into account this specific aws lambda documentation.

    I recreated the project with this command mn create-app micronaut-poc --features aws-api-gateway -l kotlin

    Now I have a "normal" REST application with two controllers:

    @Controller("/")
    class PingController {
    
        @Get("/")
        fun index(): String {
            return "{\"pong\":true}"
        }
    }
    
    @Controller("/")
    class PongController {
    
        @Post("/")
        fun post(): String {
            println("PONG!!!!!!!")
            return "{\"ping\":true}"
        }
    }
    

    The magic happens in the AWS API Gateway configuration. We have to configure a proxy resource:

    enter image description here

    Finally we can invoke the lambda from the API Gateway setting the correct HTTP Method. IMPORTANT: Set a host header, otherwise Micronaut will throw a nullpointerexception:

    GET:

    enter image description here

    POST:

    enter image description here