Alper merhaba,
guzel bir is cikarmissin keyifle okudum ve test ettim. Sanirim ihtiyaci olan herkes kodlarinizdan ve mimarinizden faydalanabilir ve sanirim bazi feedback'lara aciksiniz. O nedenle yazmak isitedim.
Oncelikle dilerseniz Reddit veya Twitter uzerinde de tag'layarak daha buyuk bir Go camiasinin kodlarinizdan haberdar olmaasini da saglayabilirsiniz. Reddit veya Twitter uzerinde paylasim yaptiginizda #golang etiketini tag'ladiginizda auto-bot'larin bunu anons ettigini saniyorum, daha fazla feedback icin iyi olabilir :)
Kod kismina gelecek olursak, Microservice yaklasimi da guzel olabilirdi. Yani tek bir isi yapan butun kodlarin run oldugu main.go yerine bazi fonksiyonlari package olarak kullanarak aktif pasif sekilde rebuild edebilirsiniz.Ornegin bir kullanici PostgreSQL kullanmak istemiyorsa "package postgresql" iptal edebilir ve kendi MySQL fonksiyonlarini yazarak "package mysql" import edebilirdi. Bu da structure olarak soyle olabilir.
$ mkdir go-crud-boilerplate
$ cd go-crud-boilerplate
$ mkdir -p platform platform/postgresql platform/nats platform/redis platform/minio
Her mikroservisin kendi kodu package postgresql package nats package redis package minio gibi baslar ve ana main.go uzerinde
import (
"platform/postgresql"
"platform/nats"
"platform/redis"
"platform/minio"
)
bu sekilde import edebilirdiniz. Bu sayede Go'nun package yapisini da kullanmis olur ve daha mikro fonksiyonlari etkin kilmis olurdunuz. Bence tum route tanimlarini ornegin yeni bir route() fonksiyonu cagirarak burada tanimlayabilirsiniz.
func routes() {
r := gin.Default()
r.GET("/", home)
r.GET("/products", GetProductsHandler)
r.GET(" /cache/:cache_id ", GetProductByCacheIdHandler)
r.POST("/products", CreateProductHandler)
r.DELETE("/products/:id", DeleteProductHandler)
/products/:id
r.StaticFS("/file", http.Dir("upload"))
r.Run("
127.0.0.1:9090")
}
func main() {
routes()
}
Bu sayede hem yeni bir path endpoint eklemek daha pratik olur hem de / path home fonksiyonuna atanarak dilerseniz .html .js gibi statik icerikleri ornegin templates gibi bir klasor icerisinden cagirabilirsiniz.
Middleware kisminda (sanirim Go Web Development jargonunda buna middleware deniyor) da belki bir statisFS tanimlanmasi ve her product nesnesi icin otomatik bir page yaratilmasi iyi olabilirdi. r.StaticFS ile /product gibi bir tanim yaparak http.Dir ile her urun icin bir url olusturabilirsiniz. CreateProductHandler endpoint her cagirildiginda
c.JSON(http.StatusOK, gin.H{"product": path})
seklinde her eklenen urun icin ornegin
http://localhost:9090/product/urun seklinde bir url olusturabilir hatta bu URL bilgisini product = url seklinde Redis uzerinde tutabilirsiniz ve frontend implementasyonu cok daha kolay olur :)
CORS implementasyonlarinda artik POST DELETE gibi isleri basit dahi olsa bir auth mekanizmasi ile yapiyorlar. Ben de gecen yaptigim bir projede eger JWT kullanmiyorsam bu yonde bir degisiklige gittim. Bunun icin bir auth fonksiyonu yaratiyorsunuz ve sonrasinda ornegin r.DELETE kismi su sekilde oluyor:
r.DELETE("/products/:id", basicAuth, DeleteProductHandler)
basit auth islemi icin ornek fonksiyon:
func basicAuth(c *gin.Context) {
user, password, pasAuth := c.Request.BasicAuth()
if pasAuth && user == "username" && password == "password" {
log.WithFields(log.Fields{
"user": user,
}).Info("Kullanici dogrulandi.")
} else {
c.Abort()
c.Writer.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
return
}
}
Bundan sonra DELETE edilecek REST request'lerin basina username password ekleniyor.
$ curl -X GET "http://username:password@localhost:9090//products/:id
Bu veya baska yontemler ornegin JWT ya da belki SQL uzerinde bir token tutarak ya da bu bir User Authentication gerektiren sistemse POST DELETE fonksiyonlarinin cagirdigi fonksiyona kullanicinin servisi cagirmasi icin auth olma sarti getirilebilir.
Son olarak eger Github ve Docker Hub kullaniyorsaniz belki de pipeline entegre edebilirsiniz. Sanirim .github/workflows/ diye bir folder icerisinde ornegin create.yml dosyasini olusturarak ve Docker Hub uzerinde bir Token olusturup bunu da kullanarak siz git push ettikten sonra GitHub Actions once kendisi pipeline yaratarak ERR PASS alabilir ve bundan sonra Docker Hub uzerinde otomatik yeni tag ile yaziliminiz olusturulabilir :)
Umarim uzun bir mail olmamistir ve size bazi fikirler paylasabilmisimdir.
Happy Coding!
-- Ozgur