Desenvolvimento sem servidor com Kotlin, AWS Lambda e MongoDB Atlas
Avalie esse Tutorial
Como visto em um tutorial anteriordo, criar uma função sem servidor para o AWS Lambda com Java e MongoDB não é uma tarefa muito complicada. Na verdade, você pode fazer isso com cerca 35 linhas de código!
No entanto, talvez sua pilha não consista em Java, mas sim em Kotlin. O que precisa ser feito para usar o Kotlin para o desenvolvimento do Amazon Web Services Lambda e MongoDB ? A boa nova não é muito será diferente!
Neste tutorial, veremos como criar uma função simples do AWS Lambda. Ele usará o Kotlin como linguagem de programação e o driver Kotlin do MongoDB para interagir com o MongoDB.
Existem alguns pré-requisitos que devem ser atendidos para ter sucesso com este tutorial específico:
- Deve ter um ambiente de desenvolvimento Kotlin instalado e configurado em seu computador local.
- Deve ter uma conta da Amazon Web Services (AWS).
A maneira mais fácil de desenvolver com o Kotlin é por meio do IntelliJ, mas é uma questão de preferência. O requisito é que você possa construir aplicativos Kotlin com Gradle.
Para os fins deste tutorial, qualquer instância do MongoDB Atlas será suficiente, seja a camada gratuita M0 , a camada de pagamento por uso sem servidor ou qualquer outra coisa. No entanto, você precisará ter a instância configurada corretamente com regras de usuário e regras de acesso à rede. Se precisar de ajuda, use nosso tutorial do MongoDB Atlas como ponto de partida.
Supondo que você tenha um projeto criado usando a ferramenta de sua escolha, precisamos configurar adequadamente o arquivobuild.gradle.kts com as dependências corretas para o AWS Lambda com MongoDB.
No arquivobuild.gradle.kts, inclua o seguinte:
1 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 3 plugins { 4 kotlin("jvm") version "1.9.0" 5 application 6 id("com.github.johnrengelman.shadow") version "7.1.2" 7 } 8 9 application { 10 mainClass.set("example.Handler") 11 } 12 13 group = "org.example" 14 version = "1.0-SNAPSHOT" 15 16 repositories { 17 mavenCentral() 18 } 19 20 dependencies { 21 testImplementation(kotlin("test")) 22 implementation("com.amazonaws:aws-lambda-java-core:1.2.2") 23 implementation("com.amazonaws:aws-lambda-java-events:3.11.1") 24 implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1") 25 implementation("org.mongodb:bson:4.10.2") 26 implementation("org.mongodb:mongodb-driver-kotlin-sync:4.10.2") 27 } 28 29 tasks.test { 30 useJUnitPlatform() 31 } 32 33 tasks.withType<KotlinCompile> { 34 kotlinOptions.jvmTarget = "1.8" 35 }
Existem alguns itens dignos de nota na configuração acima.
1 plugins { 2 kotlin("jvm") version "1.9.0" 3 application 4 id("com.github.johnrengelman.shadow") version "7.1.2" 5 }
O AWS Lambda espera um ZIP ou um JAR. Usando o plug-in Shadow, podemos usar o Gradle para criar um JAR "gordo", que inclui o aplicativo e todas as dependências necessárias. Ao usar o shadow, a classe principal deve ser definida.
Para definir a classe principal, temos o seguinte:
1 application { 2 mainClass.set("example.Handler") 3 }
O acima pressupõe que todo o nosso código existirá em uma classe
Handler
em um pacoteexample
. O seu não precisa corresponder, mas observe que esta classe e pacote específicos serão referenciados ao longo do tutorial. Você deve trocar nomes sempre que necessário.O próximo item a ser observado é o bloco
dependencies
:1 dependencies { 2 testImplementation(kotlin("test")) 3 implementation("com.amazonaws:aws-lambda-java-core:1.2.2") 4 implementation("com.amazonaws:aws-lambda-java-events:3.11.1") 5 implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1") 6 implementation("org.mongodb:bson:4.10.2") 7 implementation("org.mongodb:mongodb-driver-kotlin-sync:4.10.2") 8 }
No bloco acima, estamos incluindo os vários pacotes do AWS Lambda SDK, bem como o driver MongoDB Kotlin. Essas dependências nos permitirão usar o MongoDB com Kotlin e AWS Lambda.
Se você quisesse, poderia executar o seguinte comando:
1 ./gradlew shadowJar
Desde que a classe principal exista, ela deverá construir um arquivo JAR para você.
Com os itens de configuração resolvidos, podemos nos concentrar no desenvolvimento de nossa função sem servidor. Abra o arquivosrc/main/kotlin/example/Handler.ktdo projeto e inclua o seguinte código boilerplate:
1 package example 2 3 import com.amazonaws.services.lambda.runtime.Context 4 import com.amazonaws.services.lambda.runtime.RequestHandler 5 import com.mongodb.client.model.Filters 6 import com.mongodb.kotlin.client.MongoClient 7 import com.mongodb.kotlin.client.MongoCollection 8 import com.mongodb.kotlin.client.MongoDatabase 9 import org.bson.Document 10 import org.bson.conversions.Bson 11 import org.bson.BsonDocument 12 13 class Handler : RequestHandler<Map<String, String>, Void> { 14 15 override fun handleRequest(input: Map<String, String>, context: Context): void { 16 17 return null; 18 19 } 20 }
O código acima não fará muito se você tentar executá-lo no Amazon Web Services Lambda, mas é um ponto de partida. Vamos começar estabelecendo uma conexão com o MongoDB.
Na classe
Handler
, adicione o seguinte:1 class Handler : RequestHandler<Map<String, String>, Void> { 2 3 private val mongoClient: MongoClient = MongoClient.create(System.getenv("MONGODB_ATLAS_URI")) 4 5 override fun handleRequest(input: Map<String, String>, context: Context): void { 6 7 val database: MongoDatabase = mongoClient.getDatabase("sample_mflix") 8 val collection: MongoCollection<Document> = database.getCollection("movies") 9 10 return null; 11 12 } 13 }
Primeiro, você notará que estamos criando uma variável
mongoClient
para manter as informações sobre nossa conexão. Esse cliente será criado usando um URI do MongoDB Atlas que planejamos armazenar como uma variável de ambiente. É altamente recomendável usar variáveis de ambiente para armazenar essas informações para que suas credenciais não sejam adicionadas ao seu controle de versão.Caso não tenha certeza da aparência do URI do MongoDB Atlas, ele se parece com o seguinte:
1 mongodb+srv://<username>:<password>@<clustername>.dmhrr.mongodb.net/?retryWrites=true&w=majority
Você pode encontrar sua connection string exata usando a CLI do MongoDB Atlas ou por meio do dashboard do MongoDB Atlas.
Dentro da função
handleRequest
, obtemos uma referência ao banco de dados e à coleção que queremos usar:1 val database: MongoDatabase = mongoClient.getDatabase("sample_mflix") 2 val collection: MongoCollection<Document> = database.getCollection("movies")
Para este exemplo específico, estamos usando o banco de dados
sample_mflix
e a collectionmovies
, ambos fazem parte do conjunto de dados de amostraopcional do MongoDB Atlas. Sinta-se livre para usar um banco de dados e uma coleção que você já tenha.Agora podemos nos concentrar em interações com o MongoDB. Faça algumas alterações na classe
Handler
para que ela fique assim:1 package example 2 3 import com.amazonaws.services.lambda.runtime.Context 4 import com.amazonaws.services.lambda.runtime.RequestHandler 5 import com.mongodb.client.model.Filters 6 import com.mongodb.kotlin.client.MongoClient 7 import com.mongodb.kotlin.client.MongoCollection 8 import com.mongodb.kotlin.client.MongoDatabase 9 import org.bson.Document 10 import org.bson.conversions.Bson 11 import org.bson.BsonDocument 12 13 class Handler : RequestHandler<Map<String, String>, List<Document>> { 14 15 private val mongoClient: MongoClient = MongoClient.create(System.getenv("MONGODB_ATLAS_URI")) 16 17 override fun handleRequest(input: Map<String, String>, context: Context): List<Document> { 18 19 val database: MongoDatabase = mongoClient.getDatabase("sample_mflix") 20 val collection: MongoCollection<Document> = database.getCollection("movies") 21 22 var filter: Bson = BsonDocument() 23 24 if(input.containsKey("title") && !input.get("title").isNullOrEmpty()) { 25 filter = Filters.eq("title", input.get("title")) 26 } 27 28 val results: List<Document> = collection.find(filter).limit(5).toList() 29 30 return results; 31 32 } 33 }
Em vez de usar
Void
no RequestHandler
e void
como o tipo de retorno para a funçãohandleRequest
, agora estamos usando List<Document>
porque planejamos retornar uma array de documentos ao cliente solicitante.Isso nos leva ao seguinte:
1 var filter: Bson = BsonDocument() 2 3 if(input.containsKey("title") && !input.get("title").isNullOrEmpty()) { 4 filter = Filters.eq("title", input.get("title")) 5 } 6 7 val results: List<Document> = collection.find(filter).limit(5).toList() 8 9 return results;
Em vez de executar uma query fixa quando a função é invocada, aceitamos entradas do usuário. Se o usuário fornecer um campo
title
com a invocação, construiremos um filtro para ele. Em outras palavras, procuraremos filmes com um título que corresponda à entrada do usuário. Se nenhum title
for fornecido, apenas consultaremos todos os documentos na collection.Para a operação
find
real, em vez de correr o risco de retornar mais de mil documentos, estamos limitando o conjunto de resultados a cinco e convertendo a resposta de um cursor para uma lista.Neste ponto, nossa função simples do AWS Lambda está concluída. Podemos nos concentrar na criação e implantação da função agora.
Antes de nos preocuparmos com o AWS Lambda, vamos construir o projeto utilizando a sombra. Na linha de comando, IntelliJ, ou com qualquer ferramenta que você esteja usando, execute o seguinte:
1 ./gradlew shadowJar
Encontre o arquivo JAR, que provavelmente está no diretóriobuild/libs, a menos que você especifique o contrário.
Tudo o que fizermos a seguir será feito no portal da AWS. Há três itens principais que queremos cuidar durante esse processo:
- Adicione a variável de ambiente com o URI do MongoDB Atlas à função do Lambda.
- Renomeie as informações do "Manipulador" no Lambda para refletir o projeto real.
- Carregue o arquivo JAR para o AWS Lambda.
No painel do AWS Lambda para sua função, clique na guia "Configuration (Configuração)", seguida do item de navegação "Environment Variables (Variáveis de ambiente)". Adicione
MONGODB_ATLAS_URI
junto com a string de conexão apropriada quando solicitado. Certifique-se de que a cadeia de conexão reflita sua instância com o nome de usuário e a senha adequados.Agora você pode fazer upload do arquivo JAR na aba "Código" do dashboard do AWS Lambda. Quando isso for feito, precisamos informar ao AWS Lambda qual é a classe principal e a função que deve ser executada.
Na aba “Código”, procure por “Configurações de tempo de execução” e opte por editá-lo. Em nosso exemplo, tivemos exemplo como pacote e Handler como classe. Também tivemos nossa lógica de função na funçãohandleRequest.
Com tudo isso em mente, altere o "Handler" no AWS Lambda para example.Handler::handleRequest ou o que fizer sentido para o seu projeto.
Neste ponto, você deve ser capaz de testar sua função.
Na aba "Test" do dashboard do AWS Lambda, opte por executar um teste como está. Você deve obter no máximo cinco resultados de volta. Próximo, tente usar os seguintes critérios de entrada:
1 { 2 "title": "The Terminator" 3 }
Sua resposta agora parecerá diferente por causa do filtro.
Parabéns! Você criou sua primeira função do AWS Lambda em Kotlin e essa função permite comunicação com o MongoDB!
Embora este exemplo tenha sido projetado para ser curto e simples, você pode adicionar significativamente mais lógica às suas funções que se envolvem com outras funcionalidades do MongoDB, como agregações e muito mais.
Se você quiser ver como usar o Java para fazer a mesma coisa, confira meu tutorial anterior sobre o assunto intitulado Desenvolvimento sem servidor com AWS Lambda e MongoDB Atlas usando Java.