Go ile Gin/MongoDB kullanarak RESTful API Oluşturma

Burak Tabakogluu
GoTurkiye
Published in
7 min readJul 28, 2023

MongoDB Nedir?

MongoDB, açık kaynaklı ve belge tabanlı bir NoSQL (Not Only SQL) veritabanı sistemidir. NoSQL veritabanları, geleneksel SQL tabanlı veritabanlarından farklı olarak ilişkisel veri tabanları ve tablolar yerine, belge ve koleksiyonlar üzerinde çalışır.

MongoDB, JSON benzeri belge formatı olan BSON (Binary JSON) formatını kullanır. Her belge, bir koleksiyon içinde depolanır ve BSON formatında anahtar-değer çiftleriyle temsil edilir. Bir MongoDB veritabanında, farklı yapıya sahip belgeler aynı koleksiyon içinde depolanabilir.

MongoDB’nin temel özellikleri şunlardır:

  1. Yüksek Performans: Hızlı okuma ve yazma işlemleri sağlayan hafıza tabanlı bir mimariye sahiptir.
  2. Ölçeklenebilirlik: Veri miktarı arttıkça , kolayca ölçeklenebilir ve yüksek performanslı olmaya devam eder.
  3. Esneklik: İlişkisel veritabanlarından farklı olarak, MongoDB’de verilerdeki yapı değişiklikleri kolayca yapılabilir.
  4. Belge Tabanlı: Her belge kendi içinde tutulduğu için verilerin alınması ve güncellenmesi hızlıdır.
  5. Yüksek Kullanılabilirlik: Veriler, birden fazla sunucuda replikasyon (çoklama) yaparak yüksek kullanılabilirlik sağlayabilir.
  6. Dağıtık Sistem: MongoDB, birden fazla sunucuda dağıtık veritabanı oluşturmayı destekler.

Gin Nedir ?

Gin , Go dilinde yazılmış açık kaynaklı bir web framework’üdür. Gin, Go dilinin hızına ve verimliliğine katkıda bulunarak, web uygulamaları ve API’lerinin hızlı bir şekilde geliştirilmesine yardımcı olmak için tasarlanmıştır.

Gin’in bazı özellikleri şunlardır:

  1. Performans Odaklı: Gin, Go dilinin hızlı olmasını koruyarak yüksek performanslı web uygulamaları oluşturmayı hedefler. Diğer bazı web framework’lerinden daha hızlı çalışabilir.
  2. Minimal ve Hafif: Gin, küçük ve hafif bir framework’tür. Kod temizliği ve basitliği, başlangıçta daha az karmaşıklığa ve kullanım kolaylığına olanak tanır.
  3. HTTP Rotalama: Gin, HTTP taleplerini işlemek için etkili bir yönlendirme (routing) motoruna sahiptir. URL’lerin, belirli işlevlere eşlenmesini sağlayarak web uygulamalarının davranışlarını yönetebilir.
  4. Middlewares (Ara Katmanlar): Gin, ara katmanları kullanarak HTTP taleplerini işleme ve yanıtları düzenleme yeteneği sağlar. Bu, kimlik doğrulama, güvenlik, hata işleme gibi ortak görevleri kolayca yerine getirmenize yardımcı olur.
  5. JSON Desteği: Geliştiricilerin genellikle web servislerinde kullandığı JSON formatını kolayca destekler. JSON’ları otomatik olarak dönüştürmek için kolay ve hızlı yöntemler sağlar.
  6. Validation (Doğrulama): Gelen verileri doğrulamak için çeşitli yöntemler sağlar. Bu, istemci tarafından gönderilen verileri hatalı veya eksik girişlere karşı koruma altına almanızı sağlar.
  7. Gruplama (Grouping): Rotaları gruplayarak kodu düzenlemeyi ve ilişkili işlemleri kolayca yönetmeyi sağlar. Bu, büyük ve karmaşık uygulamalarda kullanışlı olabilir.

Uygulamaya başlamadan önce yapmanız gerekenler

MongoDB sayfasından ücretsiz bir şekilde kayıt olmalısınız.

https://www.mongodb.com/

Kayıt işlemi tamamlandıktan sonra aşağıdaki süreci izleyebilirsiniz

Projeye isim veriyoruz
Build a Database sekmesine tıklıyoruz
M0 FREE yazan yere tıklıyoruz
Kullanıcı adı ve şifre belirliyoruz
Go sürümünüze göre ayarlayıp aşağıdaki mongodb+srv yazısında okla gösterilen yere tıklayıp kopyalıyoruz

Kodlamaya başlayabiliriz

İlk olarak proje içerisinde .env adında bir dosya oluşturuyoruz ve kopyaladığımız url’yi aşağıda görüldüğü gibi kayıt ediyoruz.

2.Env dosyasından bağlantımızı çekmek için aşağıdaki bağlantıyı import edip ortam değişkenlerine ulaşıyoruz.

import "github.com/joho/godotenv"
package configs

import (
"log"
"os"

"github.com/joho/godotenv"
)

func MongoURI() string {
//burada .env dosyasındaki DB değişkenini okuyoruz
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}

uri := os.Getenv("MONGODB")
if uri == "" {
log.Fatal("MONGODB environment variable not set")
}

return uri
}

3.MongoDB bağlantımı kuruyoruz.

var db *mongo.Client

// GetDB, veritabanı bağlantısı
func GetDB() *mongo.Client {
if db == nil {
db = ConnectDatabase()
}
return db
}

// ConnectDatabase, MongoDB veritabanına bağlantı sağlayan fonksiyon.
func ConnectDatabase() *mongo.Client {
clientOptions := options.Client().ApplyURI(MongoURI())
client, err := mongo.Connect(context.Background(), clientOptions)
if err != nil {
log.Fatal(err)
}

// Veritabanına ping atarak bağlantıyı test ediyoruz.
err = client.Ping(context.Background(), nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("MongoDB'ye bağlandi.")
return client
}

// GetCollection, belirtilen koleksiyona olan bağlantıyı döndürür.
func GetCollection(client *mongo.Client, collectionName string) *mongo.Collection {
// client.Database("goTurkiye") ile veritabanına bağlanılır ve
// collectionName ile belirtilen koleksiyona erişim sağlanır.
collection := client.Database("goTurkiye").Collection(collectionName)
return collection
}

4.CRUD işlemlerini gerçekleştireceğimiz User modelimizi oluşturuyoruz.

import (
"time"

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

type User struct {
ID primitive.ObjectID `json:"id,omitempty"`
FirstName string `json:"firstname,omitempty" validate:"required"`
LastName string `json:"lastname,omitempty" validate:"required"`
Email string `json:"email,omitempty" validate:"required"`
CreateAt time.Time `json:"createAt"`
UpdateAt time.Time `json:"updateAt"`
}

5.Controller dosyamızı oluşturuyoruz ilk olarak CreateUser(kullanıcı oluşturma) CreateUser sayesinde kullanıcı oluşturma işlemlerini gerçekleştiriyoruz.

import (
"github.com/buraktabakoglu/CrudExample/configs"
"github.com/buraktabakoglu/CrudExample/models"
"context"
"net/http"
"time"

"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"gopkg.in/go-playground/validator.v9"
"gopkg.in/mgo.v2/bson"


)

// userCollection değişkeni, MongoDB "users" koleksiyonuna erişim için kullanılır
var userCollection = configs.GetCollection(configs.GetDB(), "users")

// validate, kullanıcı girdilerini doğrulamak için kullanılan validator nesnesini temsil eder
var validate = validator.New()


func CreateUser(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

var user models.User

// İstek gövdesini kullanıcı modeline bağlar ve hataları kontrol eder
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": "error", "error": err.Error()})
return
}

// Kullanıcı girdilerini doğrulamak için validator kütüphanesini kullanır
if validationErr := validate.Struct(&user); validationErr != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": "error", "error": validationErr.Error()})
return
}

// Yeni bir User nesnesi oluşturur
newUser := models.User{
ID: primitive.NewObjectID(),
FirstName: user.FirstName,
LastName: user.LastName,
Email: user.Email,
}

// Oluşturulan kullanıcıyı MongoDB'ye ekler ve sonucu döndürür
result, err := userCollection.InsertOne(ctx, newUser)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": "error", "error": err.Error()})
return
}

c.JSON(http.StatusCreated, gin.H{"message": "success", "data": result})
}

6.GetUser sayesinde kayıt ettiğimin kullanıcıları görüntüleme şansımız olucak.

func GetUser(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

// Kullanıcı ID'sini alır (örneğin /user/:id)
userID := c.Param("id")

// ID'yi ObjectId'ye dönüştürür
objectID, err := primitive.ObjectIDFromHex(userID)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": "error", "error": "Geçersiz user ID"})
return
}

// MongoDB'den kullanıcı verilerini alır
var user models.User
err = userCollection.FindOne(ctx, bson.M{"_id": objectID}).Decode(&user)
if err != nil {
if err == mongo.ErrNoDocuments {
c.JSON(http.StatusNotFound, gin.H{"message": "error", "error": "Kullanici bulunamadi"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"message": "error", "error": err.Error()})
return
}

c.JSON(http.StatusOK, gin.H{"message": "success", "User İnfo": user})
}

7.UpdateUser sayesinde kayıt ettiğimin kullanıcıların isimlerini,mail adreslerini değiştirebiliriz.

func UpdateUser(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

// Kullanıcı ID'sini alır (örneğin /user/:id)
userID := c.Param("id")

// ID'yi ObjectId'ye dönüştürür
objectID, err := primitive.ObjectIDFromHex(userID)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": "error", "error": "Invalid user ID"})
return
}

var user models.User

// İstek gövdesini kullanıcı modeline bağlar ve hataları kontrol eder
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": "error", "error": err.Error()})
return
}

// Kullanıcı girdilerini doğrulamak için validator kütüphanesini kullanır
if validationErr := validate.Struct(&user); validationErr != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": "error", "error": validationErr.Error()})
return
}

// Güncellenecek alanları belirler
update := bson.M{
"$set": bson.M{
"FirstName": user.FirstName,
"LastName": user.LastName,
"Email": user.Email,
},
}

// MongoDB'de kullanıcı verilerini günceller
_, err = userCollection.UpdateOne(ctx, bson.M{"_id": objectID}, update)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": "error", "error": err.Error()})
return
}

c.JSON(http.StatusOK, gin.H{"message": "success"})
}

8.DeleteUser sayesinde kayıt etmiş olduğumuz kullanıcıları Database’den silme işlemlerini gerçekleştirebiliriz.


func DeleteUser(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

// Kullanıcı ID'sini alır (örneğin /user/:id)
userID := c.Param("id")

// ID'yi ObjectId'ye dönüştürür
objectID, err := primitive.ObjectIDFromHex(userID)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": "error", "error": "Invalid user ID"})
return
}

// MongoDB'den kullanıcı verilerini siler
_, err = userCollection.DeleteOne(ctx, bson.M{"_id": objectID})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": "error", "error": err.Error()})
return
}

c.JSON(http.StatusOK, gin.H{"message": "success"})
}

9.Endpointlerimizi düzenliyoruz.


import (
"github.com/buraktabakoglu/CrudExample/controllers"
"github.com/gin-gonic/gin"
)

// UserRouter, kullanıcı ile ilgili tüm endpointleri yöneten fonksiyon.
func UserRouter(router *gin.Engine) {
router.POST("/user", controllers.CreateUser)
router.GET("/user/:id", controllers.GetUser)
router.PATCH("/user/:id", controllers.UpdateUser)
router.DELETE("/user/:id", controllers.DeleteUser)
}

10.Son olarak main dosyamıza giderek aşağıdaki gibi düzenliyoruz.

func main() {
// Gin framework'ünü kullanarak bir HTTP yönlendirici oluşturuyoruz.
router := gin.Default()

// configs paketinde tanımlanan GetDB fonksiyonunu çağırarak, veritabanı bağlantısını alıyoruz.
// Bu fonksiyon olası hata durumlarını da ele alıp veritabanı bağlantısını geri döndürür.
configs.GetDB()

// routes paketinde tanımlanan UserRouter fonksiyonu ile kullanıcıyla ilgili HTTP isteklerini
// yönlendiren ve işleyen route'ları ekliyoruz.
routes.UserRouter(router)

// Yönlendiriciyi belirtilen port (8080) üzerinden çalıştırıyoruz.
router.Run(":8080")
}

Terminal üzerinden “go run main.go” komutunu çalıştırıyoruz.Uygulama, belirtilen 8080 portu üzerinden HTTP isteklerini dinleyip işlemeye başladı. Artık web sunucusu kullanıma hazır durumda

[GIN-debug] POST   /user                     --> github.com/buraktabakoglu/CrudExample/controllers.CreateUser (3 handlers)
[GIN-debug] GET /user/:id --> github.com/buraktabakoglu/CrudExample/controllers.GetUser (3 handlers)
[GIN-debug] PATCH /user/:id --> github.com/buraktabakoglu/CrudExample/controllers.UpdateUser (3 handlers)
[GIN-debug] DELETE /user/:id --> github.com/buraktabakoglu/CrudExample/controllers.DeleteUser (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :8080

Postman ile localhost:8080 bağlantısıyla işlemleri gerçekleştiriyoruz

1-Kullanıcı Oluşturma işlemi

Yukarıda endpointleri oluşturduğumuz UserRouter’da Create işlemi aşağıda gibi gözükmektedir

router.POST("/user", controllers.CreateUser)

Postman üzerinden yukarıdaki şekilde firtname,lastname,email bilgilerini girip Send diyoruz ve aşağıdaki InsertedID’yi elde ediyoruz. Birde MongoDB tarafına bakalım.

Oluşturduğumuz kullanıcıyı burada görüntüleyebiliyoruz ve işlemin başarıyla gerçekleştiğini anlıyoruz.

2.Kullanıcı Bulma işlemi

router.GET("/user/:id", controllers.GetUser)

İşlemi gerçekleştirmek için Postman’den “id” değerini verip GET isteğinde bulunuyoruz. ve aşağıda bulunun User İnfo responsunu alıyoruz.

3- Kullanıcı Bilgilerini düzenleme işlemi

router.PATCH("/user/:id", controllers.UpdateUser)

İşlemi gerçekleştirmek için Postman üzerinden tekrar “id” verip body kısmına değiştirmek istediğimiz yeni değeri yazıyoruz ve PATCH işlemi gerçekleştiriyoruz ve MongoDB üzerinden kontrol ediyoruz.

MongoDB üzerinden kontrol ediyoruz.

işlem başarıyla gerçekleşti.

4-Kullanıcı Silme işlemi

router.DELETE("/user/:id", controllers.DeleteUser)

İşlemi gerçekleştirmek için Postman üzerinden tekrar “id” verip DELETE isteği gönderiyoruz ve MongoDB üzerinden kontrol ediyoruz.

MongoDB üzerinden kontrol ediyoruz.

Oluşturduğumuz Kullanıcı artık MongoDB’den kaldırıldı.

Bu makalemde MongoDB ve GİN Framework’ünü kullanarak giriş seviye Go dilinde CRUD işlemleri gerçekleştirdik.

Okuduğunuz için teşekkür ederim….

--

--