Conectando o banco de dados à API

Conectando o banco de dados à API

Olá pessoal! Bem-vindos ao artigo desta semana.
Você pode consultar os artigos anteriores aqui e o código está disponível no meu GitHub, basta acessar aqui.


A API que criamos está funcionando bem, mas tem um pequeno problema: toda vez que reiniciamos a aplicação, os dados cadastrados são perdidos. Isso não é prático nem reflete o que acontece numa aplicação do mundo real. Para resolver isso, vamos adicionar um banco de dados.

Na API do TV Show Buddy, vamos optar por um banco não relacional e usar o MongoDB Atlas, que é um serviço de banco de dados em nuvem. Ele facilita muito a vida de quem está começando, pois não é necessário instalar nada, e a versão gratuita já é suficiente para este projeto.

Para começar, crie uma conta no site do MongoDB Atlas e configure um cluster gratuito conforme prints abaixo.

IMPORTANTE: Lembre-se de liberar o seu IP atual para conseguir se conectar ao banco de dados dentro de “Network Access”.

Cluster criado? Show! Agora é só adicionar a dependência do MongoDB no pom.xml conforme abaixo:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

Essa dependência permite que o Spring Boot se conecte ao MongoDB e use diversas funcionalidades que facilitam o trabalho com banco de dados. Além de salvar, buscar e deletar documentos, ela também oferece recursos como consultas personalizadas, paginação (Vou voltar nesse assunto futuramente) - tudo isso sem precisar escrever muitos códigos manualmente.

E temos que adicionar uma nova classe que será responsável pela conexão com o banco. Essa é uma classe genérica e pode ser adaptada para ser utilizada em outros projetos.

@Slf4j
@Configuration
public class MongoConfig {

    @Value("${mongo.user}")
    private String mongoUser;

    @Value("${mongo.password}")
    private String mongoPassword;

    @Value("${mongo.host}")
    private String mongoHost;

    @Bean
    public MongoClient mongoClient() {
        String connectionString = String.format(
                "mongodb+srv://%s:%s@%s",
                mongoUser, mongoPassword, mongoHost
        );

        log.info("Trying to connect to MongoDB.");

        try {
            MongoClient mongoClient = MongoClients.create(connectionString);
            log.info("Connection to MongoDB successful!");
            return mongoClient;
        } catch (Exception e) {
            log.error("Failed to connect to MongoDB: {}", e.getMessage(), e);
            throw e;
        }
    }
}

E atualizar o application.properties

spring.application.name=tvshowbuddy
mongo.user=${MONGO_USER:}
mongo.password=${MONGO_PASSWORD:}
mongo.host=${MONGO_HOST:}

Para rodar a API, basta preencher as variáveis de ambiente diretamente no Intellij, adicionar o valor MONGO_USER={{seu_usuario}};MONGO_PASSWORD={{sua_senha}};MONGO_HOST={{seu_host}}
O valor do seu host pode ser obtido na opção "Connect" do seu cluster.

O próximo passo é ajustar a classe Series que criamos anteriormente para que ela represente o documento que será salvo no banco de dados.

Um documento é um registro com todas as informações que queremos guardar. Exemplo: ano de lançamento, nome da série etc.

Alteração na classe Series

A anotação @Document(collection = "series") indica que a classe Series representa um documento. O atributo collection = "series" especifica que os dados dessa classe serão armazenados na coleção chamada series. Pense na coleção como o equivalente a uma tabela em um banco de dados relacional, mas no MongoDB ela armazena documentos no formato JSON.

Já a anotação @Id marca o campo id como o identificador único do documento. No MongoDB, cada documento precisa de um identificador chamado "_id", que serve para diferenciá-lo dos demais (E usaremos ele para buscar uma série específica). No nosso caso, o id que será gerado automaticamente.

Lembra que comentei sobre o Repository?

Chegou a hora de criar a interface SeriesRepository que estende a interface genérica do MongoRepository, uma interface do Spring Data que fornece operações básicas para manipulação de documentos no MongoDB de forma simplificada e com isso já podemos utilizar os métodos abaixo:

  • save: Salva ou atualiza uma série no banco.

  • findById: Busca uma série pelo seu id.

  • findAll: Lista todas as séries.

  • deleteById: Deleta uma série pelo id.

Interface SeriesRepository

public interface SeriesRepository extends MongoRepository<Series, String> {
}

Como mostrado no código acima, ao extender o MongoRepository, devemos passar dois parâmetros:

  • Series: Indica que essa interface está lidando com a classe Series, ou seja, cada documento na coleção series será representado por um objeto Series.

  • String: Especifica que o tipo do identificador único (id) de cada documento é uma String.

E por fim vamos alterar a classe SeriesService , removendo a lista que simulava o banco de dados e adicionando a SeriesRepository que será responsável por realizar as operações no banco.

@Service
@RequiredArgsConstructor
public class SeriesService {

    private final SeriesRepository seriesRepository;

    public Series createANewSeries(Series series) {
        return seriesRepository.save(series);
    }

    public List<Series> listAllSeries() {
        return seriesRepository.findAll();
    }

    public Optional<Series> findById(String id) {
        return seriesRepository.findById(id);
    }

    public Optional<Series> updateSeries(String id, Series updatedSeries) {
        return seriesRepository.findById(id)
                .map(existingSeries -> {

                    if (updatedSeries.getName() != null && !updatedSeries.getName().trim().isEmpty()) {
                        existingSeries.setName(updatedSeries.getName());
                    }

                    if (updatedSeries.getGenre() != null && !updatedSeries.getGenre().trim().isEmpty()) {
                        existingSeries.setGenre(updatedSeries.getGenre());
                    }

                    if (updatedSeries.getReleaseYear() > 0) {
                        existingSeries.setReleaseYear(updatedSeries.getReleaseYear());
                    }

                    if (updatedSeries.getSeasons() != null && !updatedSeries.getSeasons().isEmpty()) {
                        if (existingSeries.getSeasons() == null) {
                            existingSeries.setSeasons(new ArrayList<>());
                        }

                        for (Season updatedSeason : updatedSeries.getSeasons()) {
                            Optional<Season> existingSeason = existingSeries.getSeasons()
                                    .stream()
                                    .filter(s -> s.getSeasonNumber() == updatedSeason.getSeasonNumber())
                                    .findFirst();

                            if (existingSeason.isPresent()) {
                                Season seasonToUpdate = existingSeason.get();

                                if (updatedSeason.getEpisodes() > 0) {
                                    seasonToUpdate.setEpisodes(updatedSeason.getEpisodes());
                                }
                            } else {

                                if (updatedSeason.getSeasonNumber() > 0 && updatedSeason.getEpisodes() > 0) {
                                    existingSeries.getSeasons().add(updatedSeason);
                                }
                            }
                        }

                        existingSeries.getSeasons().sort(Comparator.comparingInt(Season::getSeasonNumber));
                    }

                        return seriesRepository.save(existingSeries);
                });
    }

    public void deleteSeries(String id) {
        seriesRepository.deleteById(id);
    }
}

Por hoje é isso!
Se ficou com alguma dúvida, deixe nos comentários.

Nos vemos no próximo post! 👋