Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Junte-se a nós no Amazon Web Services re:Invent 2024! Saiba como usar o MongoDB para casos de uso de AI .
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Produtoschevron-right
MongoDBchevron-right

Como construir um aplicativo web Go com Gi, MongoDB e AI

Ado Kukic10 min read • Published Aug 30, 2024 • Updated Aug 30, 2024
GoMongoDB
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Criar aplicativos com o Go oferece muitas vantagens. A linguagem é rápida, simples e leve, ao mesmo tempo em que oferece suporte a recursos poderosos, como simultaneidade, digitação forte e uma biblioteca padrão robusta. Neste tutorial, usaremos o popular framework Gin web junto com o MongoDB para criar um aplicativo web baseado em Go.
O Gin é um framework web simples para Go que oferece uma maneira fácil de criar servidores web e APIs. Ele é rápido, leve e modular, o que o torna ideal para criar microsserviços e APIs, mas pode ser facilmente estendido para a criação de aplicativos completos.
Usaremos o Gin para criar um aplicativo Web com três endpoints que se conectam a um MongoDB database. O MongoDB é um banco de dados NoSQL orientado a documentos popular que armazena dados em documentos do tipo JSON. O MongoDB é uma ótima opção para criar aplicativos modernos.
Em vez de criar toda a aplicação manualmente, aproveitaremos um assistente de codificação de IA da Sourcegraph chamado Cody para nos ajudar a criar nossa aplicação Go. O Cody é o único assistente de IA que conhece toda a sua base de código e pode ajudar você a gravar, depurar, testar e documentar seu código. Usaremos muitos desses recursos ao desenvolvermos nosso aplicativo hoje.

Pré-requisitos

Antes de começar, você precisará:
Após atender aos pré-requisitos, você estará pronto para desenvolver. Vamos lá!

Começar

Começaremos criando um novo projeto Go para nosso aplicativo. Para este exemplo, vamos nomear o projeto mflix, então bora criar o diretório do projeto e navegar por ele:
1mkdir mflix
2cd mflix
Em seguida, inicialize um novo módulo Go, que gerenciará as dependências do nosso projeto:
1go mod init mflix
Agora que temos nosso módulo Go criado, vamos instalar as dependências do nosso projeto. Vamos mantê-lo simples e apenas instalar as bibliotecas gin e mongodb.
1go get github.com/gin-gonic/gin
2go get go.mongodb.org/mongo-driver/mongo
Com nossas dependências obtidas e instaladas, estamos prontos para começar a criar nosso aplicativo.

Configuração do aplicativo Gin com o Cody

Para começar a desenvolver nosso aplicativo, vamos criar nosso ponto de entrada criando um arquivo main.go. Em seguida, embora possamos configurar nosso aplicativo manualmente, vamos aproveitar o Cody para criar nosso ponto de partida. Na janela de bate-papo do Cody, podemos solicitar a criação de um aplicativo Go Gin básico.
Crie um novo aplicativo Gin com Cody AI
O Cody gerou um bom ponto de partida para nós. Ele importou o framework Gin, criou uma função main, e instanciou um aplicativo Gin básico com uma única rota que imprime a mensagem Hello World. Bom começo.
1package main
2
3import (
4 "github.com/gin-gonic/gin"
5)
6
7func main() {
8 r := gin.Default()
9 r.GET("/", func(c *gin.Context) {
10 c.JSON(200, gin.H{
11 "message": "Hello World",
12 })
13 })
14
15 r.Run()
16}
Vamos garantir que esse código seja executado. Inicie o servidor executando go run main.go na janela de terminal dentro do diretório mflix e, em seguida, navegue até localhost:8080, que é a porta padrão para um aplicativo Gin. Nosso código funciona e o resultado que devemos ver é:
Exemplo de saída do servidor web Gin
Temos um ótimo ponto de partida agora. A seguir, vamos adicionar nosso cliente MongoDB ao nosso aplicativo Gin. Poderíamos usar Cody novamente, mas para este, nós mesmos vamos gravar. Atualizaremos o código para o seguinte:
1package main
2
3import (
4 // Add required Go packages
5 "context"
6 "log"
7
8 "github.com/gin-gonic/gin"
9
10 // Add the MongoDB driver packages
11 "go.mongodb.org/mongo-driver/mongo"
12 "go.mongodb.org/mongo-driver/mongo/options"
13)
14
15// Your MongoDB Atlas Connection String
16const uri = "YOUR-CONNECTION-STRING-HERE"
17
18// A global variable that will hold a reference to the MongoDB client
19var mongoClient *mongo.Client
20
21
22// The init function will run before our main function to establish a connection to MongoDB. If it cannot connect it will fail and the program will exit.
23func init() {
24 if err := connect_to_mongodb(); err != nil {
25 log.Fatal("Could not connect to MongoDB")
26 }
27}
28
29func main() {
30 r := gin.Default()
31 r.GET("/", func(c *gin.Context) {
32 c.JSON(200, gin.H{
33 "message": "Hello World",
34 })
35 })
36
37 r.Run()
38}
39
40// Our implementation logic for connecting to MongoDB
41func connect_to_mongodb() error {
42 serverAPI := options.ServerAPI(options.ServerAPIVersion1)
43 opts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPI)
44
45 client, err := mongo.Connect(context.TODO(), opts)
46 if err != nil {
47 panic(err)
48 }
49 err = client.Ping(context.TODO(), nil)
50 mongoClient = client
51 return err
52}
Certifique-se de definir sua string de conexão do MongoDB Atlas na linha 12 da variável const uri. Caso contrário, o programa não será executado. Você pode obter sua string de conexão do MongoDB Atlas navegando até o dashboard do Atlas, clicando no botão "Connect" no cluster de banco de dados e selecionando o driver que está usando.
URI de conexão dentro do MongoDB Atlas
Se precisar de mais ajuda para configurar o MongoDB Atlas cluster e carregar os dados de exemplo, confira o guia"How to Use a Sample Database with MongoDB " . O banco de dados com o qual trabalharemos é chamado sample_mflix e a collection nesse banco de dados que usaremos é chamada movies. Esse conjunto de dados contém uma lista de filmes com várias informações, como roteiro, gênero, ano de lançamento e muito mais.
Conjunto de dados de amostra do MongoDB Atlas para filmes
Agora que temos nosso MongoDB database configurado em nossa aplicação Go, estamos prontos para começar a criar nossos endpoints adicionais. Como trabalharemos com o conjunto de dados de amostra que contém informações de filmes, criaremos três endpoints com base no trabalho com os dados de filmes:
  • Um endpoint para obter uma lista de todos os filmes.
  • Um endpoint para obter um único filme com base em um id fornecido.
  • Um endpoint para executar uma agregação na coleção de filmes.
Podemos fazer isso manualmente ou, se você é novo em escrever aplicativos Go, pode perguntar ao Cody. Vamos perguntar ao Cody.
Cody AI cria endpoints
Cody nos deu três endpoints prontos para uso.

Obter filmes

Esse endpoint entrará no banco de dados sample_mflix e, em seguida, na coleção movies e recuperará todos os filmes.
1// GET /movies - Get all movies
2func getMovies(c *gin.Context) {
3 // Find movies
4 cursor, err := mongoClient.Database("sample_mflix").Collection("movies").Find(context.TODO(), bson.D{{}})
5 if err != nil {
6 c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
7 return
8 }
9
10 // Map results
11 var movies []bson.M
12 if err = cursor.All(context.TODO(), &movies); err != nil {
13 c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
14 return
15 }
16
17 // Return movies
18 c.JSON(http.StatusOK, movies)
19}

Obter filme por ID

O segundo endpoint retornará um filme específico com base no id fornecido na coleção movies no banco de dados sample_mflix.
1// GET /movies/:id - Get movie by ID
2func getMovieByID(c *gin.Context) {
3 // Get movie ID from URL
4 id := c.Param("id")
5
6 // Find movie by ID
7 var movie bson.M
8 err := mongoClient.Database("sample_mflix").Collection("movies").FindOne(context.TODO(), bson.D{{"_id", id}}).Decode(&movie)
9 if err != nil {
10 c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
11 return
12 }
13
14 // Return movie
15 c.JSON(http.StatusOK, movie)
16}

Filmes agregados

O terceiro e último endpoint nos permitirá executar agregações na coleção de filmes. Operações de agregação processam diversos documentos e geram resultados calculados. Assim, com esse endpoint, o usuário final pode passar qualquer pipeline de agregação válido do MongoDB para executar várias análises na coleção movies.
Observe que as agregações são muito avançadas e, em um ambiente de produção, você provavelmente não gostaria de habilitar esse nível de acesso por meio de payloads de solicitação HTTP. Mas, para fins de execução deste tutorial, optamos por manter isso. Como tarefa de casa, para aprendizado adicional, tente usar o Cody para limitar o número de estágios ou os tipos de operações que o usuário final pode executar nesse endpoint.
1// POST /movies/aggregations - Run aggregations on movies
2func aggregateMovies(c *gin.Context) {
3 // Get aggregation pipeline from request body
4 var pipeline interface{}
5 if err := c.ShouldBindJSON(&pipeline); err != nil {
6 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
7 return
8 }
9
10 // Run aggregations
11 cursor, err := mongoClient.Database("sample_mflix").Collection("movies").Aggregate(context.TODO(), pipeline)
12 if err != nil {
13 c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
14 return
15 }
16
17 // Map results
18 var result []bson.M
19 if err = cursor.All(context.TODO(), &result); err != nil {
20 c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
21 return
22 }
23
24 // Return result
25 c.JSON(http.StatusOK, result)
26}
Agora que implementamos nossos endpoints, vamos adicioná-los ao roteador para que possamos chamá-los. Mais uma vez, podemos usar outro recurso da Cody, o preenchimento automático, para nos fornecer de forma inteligente as conclusões das declarações, de modo que não precisemos escrever todo o código.
Cody AI Autocomplete com Go
Nossa função main deve agora ter a seguinte aparência:
1func main() {
2 r := gin.Default()
3 r.GET("/", func(c *gin.Context) {
4 c.JSON(200, gin.H{
5 "message": "Hello World",
6 })
7 })
8 r.GET("/movies", getMovies)
9 r.GET("/movies/:id", getMovieByID)
10 r.POST("/movies/aggregations", aggregateMovies)
11
12 r.Run()
13}
Agora que temos nossas rotas configuradas, vamos testar nossa aplicação para garantir que tudo esteja funcionando bem. Reinicie o servidor e navegue até localhost:8080/movies. Se tudo correr bem, você verá uma grande lista de filmes retornados no formato JSON na janela do navegador. Se não vir isso, verifique o console do IDE para ver quais erros são mostrados.
Amostra de saída para o endpoint de filmes
Vamos testar o segundo endpoint. Escolha qualquer id da coleção de filmes e navegue até localhost:8080/movies/{{id} – por exemplo, localhost:8080/movies/573a1390f29313caabcd42e8. Se tudo correr bem, você verá esse único filme listado. Mas se você estiver seguindo este tutorial, na verdade, não verá o filme.
Erro nos resultados de string para ID de objeto
O problema é que, em nossa implementação da função getMovie, estamos aceitando o valor de id como uma string, enquanto o tipo de dados em nosso MongoDB database é um ObjectID. Portanto, quando executamos o método FindOne e tentamos fazer a correspondência entre o valor da string de id ao valor de ObjectID, não obtemos uma correspondência.
Vamos pedir ao Cody que nos ajude a corrigir isso, convertendo a entrada de string que recebemos em um ObjectID.
Cody AI MongoDB String para ObjectID
Nossa função getMovieByID atualizada é a seguinte:
1func getMovieByID(c *gin.Context) {
2
3 // Get movie ID from URL
4 idStr := c.Param("id")
5
6 // Convert id string to ObjectId
7 id, err := primitive.ObjectIDFromHex(idStr)
8 if err != nil {
9 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
10 return
11 }
12
13 // Find movie by ObjectId
14 var movie bson.M
15 err = mongoClient.Database("sample_mflix").Collection("movies").FindOne(context.TODO(), bson.D{{"_id", id}}).Decode(&movie)
16 if err != nil {
17 c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
18 return
19 }
20
21 // Return movie
22 c.JSON(http.StatusOK, movie)
23}
Dependendo do seu IDE, talvez seja necessário adicionar a dependência primitive em sua declaração de importação. A declaração de importação final é semelhante a:
1import (
2 "context"
3 "log"
4 "net/http"
5
6 "github.com/gin-gonic/gin"
7 "go.mongodb.org/mongo-driver/bson"
8 "go.mongodb.org/mongo-driver/bson/primitive"
9 "go.mongodb.org/mongo-driver/mongo"
10 "go.mongodb.org/mongo-driver/mongo/options"
11)
Se examinarmos o novo código fornecido pelo Cody, poderemos ver que agora estamos obtendo o valor de nosso parâmetro id e armazenando-o em uma variável chamada idStr. Em seguida, usamos o pacote primitivo para tentar converter a string em um ObjectID. Se idStr for uma string válida que possa ser convertida em ObjectID, então estaremos prontos e usaremos a nova variável id ao fazer nossa operação FindOne. Caso contrário, receberemos uma mensagem de erro de volta.
Reinicie seu servidor e agora tente obter um único resultado de filme navegando até localhost:8080/movies/ {id}.
Endpoint de resposta de um único filme
Para nosso endpoint final, estamos permitindo que o usuário final forneça um pipeline de agregação que executaremos na coleção mflix. O usuário pode fornecer qualquer agregação que desejar. Para testar esse endpoint, faremos uma solicitação POST para o localhost:8080/movies/aggregations. No corpo da solicitação, incluiremos nosso pipeline de agregação.
Endpoint de agregação Postman no MongoDB
Vamos executar uma agregação para retornar uma contagem de filmes de comédia, agrupados por ano e em ordem decrescente. Novamente, lembre-se de que as agregações são muito poderosas e podem ser usadas de forma abusiva. Normalmente, não desejamos conceder acesso direto ao usuário final para gravar e executar suas próprias agregações ad hoc em uma solicitação HTTP, a menos que seja para uma ferramenta interna ou algo do tipo. Nosso pipeline de agregação ficará assim:
1[
2 {"$match": {"genres": "Comedy"}},
3 {"$group": {
4 "_id": "$year",
5 "count": {"$sum": 1}
6 }},
7 {"$sort": {"count": -1}}
8]
Ao executar essa agregação, obteremos um conjunto de resultados com a seguinte aparência:
1[
2 {
3 "_id": 2014,
4 "count": 287
5 },
6 {
7 "_id": 2013,
8 "count": 286
9 },
10 {
11 "_id": 2009,
12 "count": 268
13 },
14 {
15 "_id": 2011,
16 "count": 263
17 },
18 {
19 "_id": 2006,
20 "count": 260
21 },
22 ...
23]
Parece que 2014 foi um grande ano para a comédia. Se você não estiver familiarizado com o funcionamento das agregações, confira os seguintes recursos:
Além disso, você pode pedir ao Cody uma explicação específica sobre como nossa função aggregateMovies funciona para entender melhor como o código é implementado usando o comando Cody /explain.
Cody AI explica o código

Código final

Escrevemos um servidor web Go usando Gin, MongoDB e Cody hoje. Embora o aplicativo possa não ser o código mais complexo, aprendemos como fazê-lo:
  • Crie rotas e endpoints usando o framework web do Gin.
  • Implementar o MongoDB em nosso aplicativo Gin.
  • Fazer queries do MongoDB para recuperar dados.
  • Executar agregações do MongoDB.
  • Aproveitar o Cody para nos ajudar a gravarr, depurar e explicar o código.
A saída final documentada de todo o código que escrevemos nesta publicação está abaixo para sua referência:
1// Declare the entry point into our application
2package main
3
4// Add our dependencies from the standard library, Gin, and MongoDB
5import (
6 "context"
7 "fmt"
8 "log"
9 "net/http"
10
11 "github.com/gin-gonic/gin"
12 "go.mongodb.org/mongo-driver/bson"
13 "go.mongodb.org/mongo-driver/bson/primitive"
14 "go.mongodb.org/mongo-driver/mongo"
15 "go.mongodb.org/mongo-driver/mongo/options"
16)
17
18// Define your MongoDB connection string
19const uri = "{YOUR-CONNECTION-STRING-HERE}"
20
21// Create a global variable to hold our MongoDB connection
22var mongoClient *mongo.Client
23
24// This function runs before we call our main function and connects to our MongoDB database. If it cannot connect, the application stops.
25func init() {
26 if err := connect_to_mongodb(); err != nil {
27 log.Fatal("Could not connect to MongoDB")
28 }
29}
30
31
32// Our entry point into our application
33func main() {
34 // The simplest way to start a Gin application using the frameworks defaults
35 r := gin.Default()
36
37 // Our route definitions
38 r.GET("/", func(c *gin.Context) {
39 c.JSON(200, gin.H{
40 "message": "Hello World",
41 })
42 })
43 r.GET("/movies", getMovies)
44 r.GET("/movies/:id", getMovieByID)
45 r.POST("/movies/aggregations", aggregateMovies)
46
47 // The Run() method starts our Gin server
48 r.Run()
49}
50
51// Implemention of the /movies route that returns all of the movies from our movies collection.
52func getMovies(c *gin.Context) {
53 // Find movies
54 cursor, err := mongoClient.Database("sample_mflix").Collection("movies").Find(context.TODO(), bson.D{{}})
55 if err != nil {
56 c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
57 return
58 }
59
60 // Map results
61 var movies []bson.M
62 if err = cursor.All(context.TODO(), &movies); err != nil {
63 c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
64 return
65 }
66
67 // Return movies
68 c.JSON(http.StatusOK, movies)
69}
70
71
72// The implementation of our /movies/{id} endpoint that returns a single movie based on the provided ID
73func getMovieByID(c *gin.Context) {
74
75 // Get movie ID from URL
76 idStr := c.Param("id")
77
78 // Convert id string to ObjectId
79 id, err := primitive.ObjectIDFromHex(idStr)
80 if err != nil {
81 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
82 return
83 }
84
85 // Find movie by ObjectId
86 var movie bson.M
87 err = mongoClient.Database("sample_mflix").Collection("movies").FindOne(context.TODO(), bson.D{{"_id", id}}).Decode(&movie)
88 if err != nil {
89 c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
90 return
91 }
92
93 // Return movie
94 c.JSON(http.StatusOK, movie)
95}
96
97// The implementation of our /movies/aggregations endpoint that allows a user to pass in an aggregation to run our the movies collection.
98func aggregateMovies(c *gin.Context) {
99 // Get aggregation pipeline from request body
100 var pipeline interface{}
101 if err := c.ShouldBindJSON(&pipeline); err != nil {
102 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
103 return
104 }
105
106 // Run aggregations
107 cursor, err := mongoClient.Database("sample_mflix").Collection("movies").Aggregate(context.TODO(), pipeline)
108 if err != nil {
109 c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
110 return
111 }
112
113 // Map results
114 var result []bson.M
115 if err = cursor.All(context.TODO(), &result); err != nil {
116 c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
117 return
118 }
119
120 // Return result
121 c.JSON(http.StatusOK, result)
122}
123
124
125// Our implementation code to connect to MongoDB at startup
126func connect_to_mongodb() error {
127 serverAPI := options.ServerAPI(options.ServerAPIVersion1)
128 opts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPI)
129
130 client, err := mongo.Connect(context.TODO(), opts)
131 if err != nil {
132 panic(err)
133 }
134 err = client.Ping(context.TODO(), nil)
135 mongoClient = client
136 return err
137}

Conclusão

O Go é uma linguagem de programação surpreendente e o Gin é um framework muito poderoso para desenvolver aplicativos web. Combinado com o MongoDB, com o driver nativo do MongoDB e com uma pequena ajuda do Cody, conseguimos criar esse aplicativo em pouco tempo.
Cody é o único assistente de AI que conhece toda a sua base de código. Neste tutorial, apenas começamos a explorar as possibilidades. Além do preenchimento automático e dos comandos que mostramos hoje, o Cody pode identificar problemas no código, documentar seu código, criar testes de unidade e oferecer suporte à criação de comandos personalizados para estendê-lo a qualquer caso de uso que você tenha. Experimente o Cody gratuitamente em cody.dev.
E se você tiver alguma dúvida ou comentário, vamos continuar a conversa em nossos fóruns de desenvolvedores!
O código inteiro do nosso aplicativo está acima, então não há repositório do GitHub para esse aplicativo simples. Feliz codificação.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Artigo

Simplificando o desenvolvimento de aplicativos Java com o MongoDB: um guia abrangente para usar testcontainers


Jul 22, 2024 | 7 min read
Tutorial

Como começar a usar o Neurelo e o MongoDB


Aug 30, 2024 | 7 min read
Tutorial

A grande migração contínua: trabalhos do CDC com o Confluent Cloud e o Relational Migrator


Aug 23, 2024 | 11 min read
Início rápido

Primeiros passos no MongoDB e Starlette


Jul 12, 2024 | 5 min read
Sumário