Een CRUD API maken met Golang's Gin en MongoDB

Een CRUD API maken met Golang's Gin en MongoDB

Golang is een van de best betalende, veelgevraagde programmeertalen met veel toepassingen. In combinatie met frameworks zoals Gin, Revel en gorilla/mux, kun je eenvoudig een API maken met Go.





Leer hoe u een CRUD API in Golang maakt met behulp van het Gin HTTP-framework.





MAKEUSEVAN VIDEO VAN DE DAG

Initiële installatie en installatie

Aan de slag met Golang door het op uw computer te installeren als u dat nog niet hebt gedaan.





Eenmaal geïnstalleerd, is de volgende stap het maken van een projecthoofdmap op uw computer en het initialiseren van een Go-module in die hoofdmap.

Om dit te doen, open een CLI , navigeer naar de hoofdmap van uw project en voer het volgende uit:



go mod init module_name 

U ziet uw modulenaam (bijv. CRUD_API ) en de versie ervan wanneer u de . opent ga.mod het dossier. Alle aangepaste pakketten komen uit deze bovenliggende module. Dus elk geïmporteerd aangepast pakket heeft de vorm:

import(package CRUD_API/package-directory-name)

Installeer vervolgens de pakketten die nodig zijn voor het maken van de CRUD API. Gebruik in dit geval Gin Gonic om de API-eindpunten te routeren:





go get github.com/gin-gonic/gin 

Installeer nu het MongoDB-stuurprogramma om gegevens op te slaan:

go get go.mongodb.org/mongo-driver/mongo

Hoe te verbinden Ga naar MongoDB

Het enige dat u nodig hebt, is uw MongoDB URI om Golang met de database te verbinden. Het ziet er meestal zo uit als u lokaal verbinding maakt met MongoDB Atlas:





Mongo_URL = "mongodb://127.0.0.1:27017"

Maak nu een nieuwe map in de hoofdmap van uw project en noem deze databases . Maak een Go-bestand in deze map en geef het een naam database.go .

Dit is uw databasepakket en het begint met het importeren van de vereiste bibliotheken:

package database 

import (
"context"
"fmt"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)

func ConnectDB() *mongo.Client {
Mongo_URL := "mongodb://127.0.0.1:27017"
client, err := mongo.NewClient(options.Client().ApplyURI(Mongo_URL))

if err != nil {
log.Fatal(err)
}

ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
err = client.Connect(ctx)
defer cancel()

if err != nil {
log.Fatal(err)
}

fmt.Println("Connected to mongoDB")
return client
}

Het is het beste om omgevingsvariabelen zoals de databaseverbindingsreeks in a . te verbergen .env het dossier het dotenv-pakket gebruiken . Dit maakt uw code draagbaarder en is handig bij het gebruik van een MongoDB cloudclusterinstantie , bijvoorbeeld.

De ConnectDB functie brengt een verbinding tot stand en retourneert een nieuw MongoDB Client-object.

Databaseverzameling maken

MongoDB slaat gegevens op in Collections, die een interface bieden naar de onderliggende databasegegevens.

Om de collectie-ophaalfunctionaliteit af te handelen, begint u met het maken van een nieuwe map, Verzameling , in uw projectroot. Maak nu een nieuw Go-bestand aan, getCollection.go , die de verzameling uit de database haalt:

package getcollection 

import (
"go.mongodb.org/mongo-driver/mongo"
)

func GetCollection(client *mongo.Client, collectionName string) *mongo.Collection {
collection := client.Database("myGoappDB").Collection("Posts")
return collection
}

Deze functie haalt de verzameling op uit de MongoDB-database. De databasenaam is in dit geval mijnGoappDB , met Berichten als zijn collectie.

Het databasemodel maken

Maak een nieuwe map in je hoofdmap en noem deze model- . Deze map behandelt uw databasemodel.

Maak een nieuw Go-bestand in die map en noem het model.go . Uw model is in dit geval een blogpost met de titel:

package model 

import (
"go.mongodb.org/mongo-driver/bson/primitive"
)

type Post struct {
ID primitive.ObjectID
Title string
Article string
}

Een CRUD API maken met Go

De volgende stap is het maken van de CRUD API. Om met deze sectie te beginnen, maakt u een nieuwe map in de hoofdmap van uw project om uw eindpunten af ​​te handelen. Noem het routes .

Maak voor elke actie een apart Go-bestand aan in deze map. U kunt ze bijvoorbeeld een naam geven create.go , lees.go , update.go , en delete.go . U exporteert deze handlers als de routes pakket.

Het POST-eindpunt maken in Go

Begin met het definiëren van het POST-eindpunt om gegevens in de database te schrijven.

Binnen routes/create.go , voeg het volgende toe:

package routes 

import (
getcollection "CRUD_API/Collection"
database "CRUD_API/databases"
model "CRUD_API/model"
"context"
"log"
"net/http"
"time"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson/primitive"
)

func CreatePost(c *gin.Context) {
var DB = database.ConnectDB()
var postCollection = getcollection.GetCollection(DB, "Posts")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
post := new(model.Posts)
defer cancel()

if err := c.BindJSON(&post); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": err})
log.Fatal(err)
return
}

postPayload := model.Posts{
Id: primitive.NewObjectID(),
Title: post.Title,
Article: post.Article,
}

result, err := postCollection.InsertOne(ctx, postPayload)

if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": err})
return
}

c.JSON(http.StatusCreated, gin.H{"message": "Posted successfully", "Data": map[string]interface{}{"data": result}})
}

Deze code begint met het importeren van de aangepaste modules van het project. Vervolgens importeert het pakketten van derden, waaronder: Gin en MongoDB-stuurprogramma .

Verder, postCollection bevat de databaseverzameling. Opmerkelijk, c.BindJSON('post') is een JSONified-modelinstantie die elk modelveld aanroept als postPayload ; dit gaat in de database.

Het GET-eindpunt maken

Het GET-eindpunt, in routes/read.go , leest een enkel document uit de database via zijn unieke ID. Het begint ook met het importeren van aangepaste pakketten en pakketten van derden:

usb-apparaat blijft loskoppelen en opnieuw verbinden windows 10
package routes 

import (
getcollection "CRUD_API/Collection"
database "CRUD_API/databases"
model "CRUD_API/model"
"context"
"net/http"
"time"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)

func ReadOnePost(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
var DB = database.ConnectDB()
var postCollection = getcollection.GetCollection(DB, "Posts")

postId := c.Param("postId")
var result model.Posts

defer cancel()

objId, _ := primitive.ObjectIDFromHex(postId)

err := postCollection.FindOne(ctx, bson.M{"id": objId}).Decode(&result)

res := map[string]interface{}{"data": result}

if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": err})
return
}

c.JSON(http.StatusCreated, gin.H{"message": "success!", "Data": res})
}

De berichten variabele is een parameterdeclaratie. Het krijgt de object-ID van een document als objId .

Echter, resultaat is een instantie van het databasemodel, dat later het geretourneerde document bevat als res .

Hoe het PUT-eindpunt te maken

De PUT-handler, in routes/update.go , is vergelijkbaar met de POST-handler. Deze keer werkt het een bestaand bericht bij met zijn unieke object-ID:

package routes 

import (
getcollection "CRUD_API/Collection"
database "CRUD_API/databases"
model "CRUD_API/model"
"context"
"net/http"
"time"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)

func UpdatePost(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
var DB = database.ConnectDB()
var postCollection = getcollection.GetCollection(DB, "Posts")

postId := c.Param("postId")
var post model.Posts

defer cancel()

objId, _ := primitive.ObjectIDFromHex(postId)

if err := c.BindJSON(&post); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": err})
return
}

edited := bson.M{"title": post.Title, "article": post.Article}

result, err := postCollection.UpdateOne(ctx, bson.M{"id": objId}, bson.M{"$set": edited})

res := map[string]interface{}{"data": result}

if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": err})
return
}

if result.MatchedCount < 1 {
c.JSON(http.StatusInternalServerError, gin.H{"message": "Data doesn't exist"})
return
}

c.JSON(http.StatusCreated, gin.H{"message": "data updated successfully!", "Data": res})
}

Een JSON-indeling van de modelinstantie ( na ) roept elk modelveld uit de database aan. De resultaatvariabele gebruikt de MongoDB $set operator om een ​​vereist document bij te werken dat wordt aangeroepen door zijn object-ID.

De resultaat.MatchedCount voorwaarde voorkomt dat de code wordt uitgevoerd als er geen record in de database is of als de doorgegeven ID ongeldig is.

Een DELETE-eindpunt maken

Het DELETE-eindpunt, in delete.go , verwijdert een document op basis van de object-ID die als URL-parameter is doorgegeven:

package routes 

import (
getcollection "CRUD_API/Collection"
database "CRUD_API/databases"
"context"
"net/http"
"time"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)

func DeletePost(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
var DB = database.ConnectDB()
postId := c.Param("postId")

var postCollection = getcollection.GetCollection(DB, "Posts")
defer cancel()
objId, _ := primitive.ObjectIDFromHex(postId)
result, err := postCollection.DeleteOne(ctx, bson.M{"id": objId})
res := map[string]interface{}{"data": result}

if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": err})
return
}

if result.DeletedCount < 1 {
c.JSON(http.StatusInternalServerError, gin.H{"message": "No data to delete"})
return
}

c.JSON(http.StatusCreated, gin.H{"message": "Article deleted successfully", "Data": res})
}

Deze code verwijdert een record met de Eén verwijderen functie. Het maakt ook gebruik van de resultaat.DeletedCount eigenschap om te voorkomen dat de code wordt uitgevoerd als de database leeg is of de object-ID ongeldig is.

Maak het API Runner-bestand aan

Maak tot slot een main.go in de hoofdmap van uw project. Uw uiteindelijke projectstructuur zou er als volgt uit moeten zien:

  Golang CRUD-projectstructuur

Dit bestand verwerkt de routeruitvoering voor elk eindpunt:

package main 

import (
routes "CRUD_API/routes"
"github.com/gin-gonic/gin"
)

func main() {
router := gin.Default()

router.POST("/", routes.CreatePost)

// called as localhost:3000/getOne/{id}
router.GET("getOne/:postId", routes.ReadOnePost)

// called as localhost:3000/update/{id}
router.PUT("/update/:postId", routes.UpdatePost)

// called as localhost:3000/delete/{id}
router.DELETE("/delete/:postId", routes.DeletePost)

router.Run("localhost: 3000")
}

Dit bestand is het hoofdpakket dat andere bestanden uitvoert. Het begint met het importeren van de route-handlers. De volgende is de router variabel, a gin instantie die de HTTP-acties oproept en elk eindpunt aanroept bij de functienaam van de routes pakket.

Uw CRUD-project loopt door localhost:3000 . Om de server te draaien en test de CRUD API , voer de volgende opdracht uit in uw basismap:

go run main.go

Verander uw Golang CRUD-project in een bruikbaar product

Je hebt met Go een CRUD API gemaakt; Gefeliciteerd! Hoewel dit een klein project is, heb je gezien wat er nodig is om reguliere HTTP-verzoeken in Go uit te voeren.

U kunt creatiever worden door dit uit te breiden tot een meer praktische toepassing die waarde biedt aan gebruikers. Go is een geschikte programmeertaal voor verschillende gebruikssituaties.