APIs REST com Java, Spring Boot e MongoDB
Maxime Beugnet4 min read • Published Oct 25, 2023 • Updated Oct 25, 2023
APLICATIVO COMPLETO
Se você quiser escrever API REST em Java na velocidade da luz, tenho o que você precisa. Escrevi este modelo para você começar. Procurei resolver o maior número possível de problemas nele.
Portanto, se você quiser escrever APIs REST em Java, clone este projeto e estará pronto para começar num instante.
1 git clone https://github.com/mongodb-developer/java-spring-boot-mongodb-starter
Isso é tudo, gente! Tudo o que você precisa está neste repositório. A seguir, explicarei alguns dos recursos e detalhes sobre esse modelo, mas fique à vontade para ignorar o que não for necessário para sua compreensão.
Todas as informações e comandos adicionais de que você precisa para iniciar este projeto estão no arquivo
README.md
, que pode ser lido no GitHub.1 package com.mongodb.starter; 2 3 import [...] 4 5 import static org.bson.codecs.configuration.CodecRegistries.fromProviders; 6 import static org.bson.codecs.configuration.CodecRegistries.fromRegistries; 7 8 9 public class MongoDBConfiguration { 10 11 12 private String connectionString; 13 14 15 public MongoClient mongoClient() { 16 CodecRegistry pojoCodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build()); 17 CodecRegistry codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry); 18 return MongoClients.create(MongoClientSettings.builder() 19 .applyConnectionString(new ConnectionString(connectionString)) 20 .codecRegistry(codecRegistry) 21 .build()); 22 } 23 24 }
A seção importante aqui, naturalmente, é a configuração do MongoDB. Em primeiro lugar, você notará que a string de conexão é automaticamente recuperada do arquivo
application.properties
e, em segundo lugar, você notará a configuração do bean MongoClient
.Um
Codec
é a interface que abstrai os processos de decodificação de um valor BSON em um objeto Java e de codificação de um objeto Java em um valor BSON.Um
CodecRegistry
contém um conjunto de instâncias do Codec
que são acessadas de acordo com as classes Java que codificam e decodificam.O driver do MongoDB é capaz de codificar e decodificar BSON para nós, portanto, não precisamos mais lidar com isso. Toda a configuração de que precisamos para que este projeto seja executado está aqui e em nenhum outro lugar.
Por nenhum motivo especial, também usei transações ACID multidocumento em alguns métodos em que poderia fazer sentido usar transações ACID. Você pode conferir todo o código na classe
MongoDBPersonRepository
.Aqui está um exemplo:
1 private static final TransactionOptions txnOptions = TransactionOptions.builder() 2 .readPreference(ReadPreference.primary()) 3 .readConcern(ReadConcern.MAJORITY) 4 .writeConcern(WriteConcern.MAJORITY) 5 .build(); 6 7 8 public List<PersonEntity> saveAll(List<PersonEntity> personEntities) { 9 try (ClientSession clientSession = client.startSession()) { 10 return clientSession.withTransaction(() -> { 11 personEntities.forEach(p -> p.setId(new ObjectId())); 12 personCollection.insertMany(clientSession, personEntities); 13 return personEntities; 14 }, txnOptions); 15 } 16 }
Como você pode ver, estou usando um try-with-resources com fechamento automático, que fechará automaticamente a sessão do cliente no final. Isso me ajuda a manter o código limpo e simples.
Alguns de vocês podem argumentar que isso é simples demais porque as transação (e operações de gravação, em geral) podem lançar exceções, e não estou lidando com nenhuma delas aqui... Vocês estão absolutamente certos e essa é uma excelente transição para a próxima parte deste artigo.
As transações no MongoDB podem gerar exceções por vários motivos, e não gostaria de entrar muito em detalhes aqui, mas como o MongoDB 3.6, qualquer operação de gravação que falhar poderá ser automaticamente repetida uma vez. E as transações não são diferentes. Consulte a documentação para retryWrites.
Se as gravações repetitivas estiverem desabilitadas ou se uma operação de gravação falhar duas vezes, o MongoDB enviará uma MongoException (extende RuntimeException) que deve ser tratada corretamente.
Felizmente, o Spring fornece a anotação
ExceptionHandler
para nos ajudar a fazer isso. Veja o código no meu controlador PersonController
. É claro que você precisará adaptar e aprimorar isso em seu projeto real, mas a ideia principal está aqui.1 2 public final ResponseEntity<Exception> handleAllExceptions(RuntimeException e) { 3 logger.error("Internal server error.", e); 4 return new ResponseEntity<>(e, HttpStatus.INTERNAL_SERVER_ERROR); 5 }
O pipeline de agregação do MongoDB é uma maneira muito poderosa e eficiente de executar suas queries complexas o mais próximo possível de seus dados para obter a máxima eficiência. Usá-la pode aliviar a carga computacional em seu aplicativo.
Só para dar um pequeno exemplo, implementei a rota
/api/persons/averageAge
para mostrar como posso recuperar a idade média das pessoas na minha coleção.1 2 public double getAverageAge() { 3 List<Bson> pipeline = List.of(group(new BsonNull(), avg("averageAge", "$age")), project(excludeId())); 4 return personCollection.aggregate(pipeline, AverageAgeDTO.class).first().averageAge(); 5 }
Além disso, você pode observar aqui que estou usando o
personCollection
, que foi inicialmente instanciado assim:1 private MongoCollection<PersonEntity> personCollection; 2 3 4 void init() { 5 personCollection = client.getDatabase("test").getCollection("persons", PersonEntity.class); 6 }
Normalmente, minha personCollection deve codificar e decodificar somente o objeto
PersonEntity
, mas você pode substituir o tipo de objeto que sua coleção está manipulando para retornar algo diferente — no meu caso, AverageAgeDTO.class
, pois não estou esperando uma classe PersonEntity
aqui, e sim um POJO que contenha apenas a idade média das minhas "pessoas".Swagger é a ferramenta de que você precisa para documentar suas API REST. Você não tem nada para fazer — a configuração é totalmente automatizada. Basta executar o servidor e navegar para http://localhost:8080/swagger-ui.html. A interface estará esperando por você.
Você pode testar as APIs REST a partir desta página da web e explorar os modelos. Não se esqueça de desativá-lo na produção. ;-)
Isso é tudo que fiz para que funcionasse:
1 <dependency> 2 <groupId>org.springdoc</groupId> 3 <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> 4 <version>2.2.0</version> 5 </dependency>
Sim, há uma seção Nyan Cat nesta publicação. Nyan Cat é amor, e você precisa de um pouco de Nyan Cat em seus projetos. :-)
Você sabia que pode substituir o logotipo do Spring Boot nos registros por praticamente qualquer coisa que quiser?
Bem, agora você sabe. Você é bem-vindo.
Dê uma olhada no arquivo
banner.txt
se quiser substituir este incrível Nyan Cat pelo seu próprio logotipo personalizado.Gosto de usar patorjk e a fonte "Epic" para cada nome de projeto. É mais fácil identificar qual arquivo de registro estou lendo no momento.
Espero que você goste do meu modelo. Posso ajudá-lo a ser mais produtivo com o MongoDB e a pilha Java.
Se você encontrar algo que pode ser melhorado, fique à vontade para abrir um problema no GitHub ou enviar diretamente uma solicitação de pull. Eles são muito bem-vindos. :-)
Se você for iniciante no MongoDB Atlas, confira nossa publicação de Início rápido para já se familiarizar com o MongoDB Atlas.