Menu
Coddy logo textTech

Dekoratör olarak Middleware

Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 97 / 107.

Middleware, Go'daki Decorator deseninin en pratik uygulamalarından biridir. Web geliştirmede, middleware fonksiyonları; logging, kimlik doğrulama veya zamanlama gibi ortak işlevleri (cross-cutting concerns), orijinal handler'ı değiştirmeden eklemek için HTTP handler'larını sarmalar.

Temel içgörü, middleware'in bir işleyici (handler) alıp eklenmiş davranışla yeni bir işleyici döndürmesidir. Bu, Decorator desenini tam olarak takip eder; giriş ve çıkışta aynı arayüz, geliştirilmiş işlevsellik ile:

type Handler func(request string) string

func LoggingMiddleware(next Handler) Handler {
    return func(request string) string {
        result := next(request)
        return "[LOG] " + result
    }
}

func AuthMiddleware(next Handler) Handler {
    return func(request string) string {
        return "[AUTH] " + next(request)
    }
}

Her bir ara katman (middleware), zincirdeki bir sonraki işleyiciyi (handler) sarmalayarak, sarmalanmış işleyiciyi çağırmadan önce veya sonra kendi davranışını ekler. Birden fazla ara katmanı bir araya getirerek üst üste ekleyebilirsiniz:

func MainHandler(request string) string {
    return "Response to: " + request
}

handler := LoggingMiddleware(AuthMiddleware(MainHandler))
fmt.Println(handler("GET /users"))
// [LOG] [AUTH] Response to: GET /users

Sarma sırası, yürütme sırasını belirler; en dıştaki ara yazılım (middleware) ilk önce çalışır. Bu desen, Go web çerçevelerinde istek işleme boru hatları (pipelines) için yaygın olarak kullanılır ve çekirdek işleyici (handler) mantığına dokunmadan işlevsellik eklemeyi veya kaldırmayı kolaylaştırır.

challenge icon

Görev

Kolay

Middleware as Decorator (Dekoratör Olarak Ara Katman) desenini kullanarak bir istek işleme hattı (pipeline) oluşturalım! Ara katman fonksiyonlarının, temel işleyici (handler) mantığını değiştirmeden zamanlama, doğrulama ve biçimlendirme gibi özellikler eklemek için işleyicileri sarmaladığı bir sistem oluşturacaksınız.

Kodunuzu üç dosya halinde düzenleyeceksiniz:

  • handler.go: İşleyici tipinizi ve istekleri işleyen temel işleyiciyi tanımlayın.

    Bir istek dizesi alan ve bir yanıt dizesi döndüren bir fonksiyon olarak Handler tipi oluşturun:

    type Handler func(request string) string

    Aldığı herhangi bir istek için Processed: [request] döndüren bir BaseHandler fonksiyonu uygulayın.

  • middleware.go: İşleyicileri ek davranışlarla sarmalayan ara katman fonksiyonlarınızı oluşturun.

    Her biri bir Handler alan ve yeni bir Handler döndüren üç ara katman fonksiyonu oluşturun:

    • TimingMiddleware — yanıtı zamanlama bilgisiyle sarmalar ve [TIMING] [response] döndürür
    • ValidationMiddleware — doğrulama öneki ekler ve [VALID] [response] döndürür
    • UppercaseMiddleware — tüm yanıtı büyük harfe dönüştürür

    Her ara katman, sarmalanmış işleyiciyi çağırmalı ve sonucunu geliştirmelidir.

  • main.go: Ara katmanları birleştirerek bir işleme hattı oluşturun.

    Uygulanacak ara katman katmanı sayısını okuyun. Ardından her katman için ara katman tipini (timing, validation veya uppercase) okuyun ve mevcut işleyicinizi bu ara katmanla sarmalayın. Bunları okundukları sırayla uygulayın; okunan ilk ara katman en dıştaki sarmalayıcı olur.

    Hattı oluşturduktan sonra istek dizesini okuyun, oluşturduğunuz işleyici aracılığıyla işleyin ve sonucu yazdırın.

Aşağıdaki girdiler sağlanacaktır:

  • Satır 1: Ara katman katmanı sayısı
  • Sonraki satırlar: Satır başına bir ara katman tipi (timing, validation veya uppercase)
  • Son satır: İşlenecek istek

Örneğin, şu girdi verildiğinde:

2
timing
validation
GET /users

Çıktınız şu olmalıdır:

[TIMING] [VALID] Processed: GET /users

Ve şu girdi verildiğinde:

3
uppercase
timing
validation
POST /data

Çıktınız şu olmalıdır:

[TIMING] [VALID] PROCESSED: POST /DATA

Ve şu girdi verildiğinde:

1
uppercase
hello world

Çıktınız şu olmalıdır:

PROCESSED: HELLO WORLD

Ve şu girdi verildiğinde:

0
simple request

Çıktınız şu olmalıdır:

Processed: simple request

Ara katman sarmalama sırasının çıktıyı nasıl etkilediğine dikkat edin; uygulanan ilk ara katman (en dıştaki) ilk çalışır ve tüm iç ara katmanlardan gelen nihai sonucu görür. İkinci örnekteki uppercase ara katmanı en son (en içte) çalışır, bu nedenle zamanlama ve doğrulama kendi öneklerini eklemeden önce temel yanıtı büyük harfe dönüştürür!

Kopya kağıdı

Go'da middleware (ara katman), orijinal işleyiciyi değiştirmeden işlevsellik eklemek için işleyicileri sarmalayarak Decorator (Dekoratör) desenini takip eder.

Bir işleyici (handler) tipini fonksiyon olarak tanımlayın:

type Handler func(request string) string

Middleware fonksiyonları bir işleyici alır ve geliştirilmiş davranışa sahip yeni bir işleyici döndürür:

func LoggingMiddleware(next Handler) Handler {
    return func(request string) string {
        result := next(request)
        return "[LOG] " + result
    }
}

func AuthMiddleware(next Handler) Handler {
    return func(request string) string {
        return "[AUTH] " + next(request)
    }
}

Birden fazla middleware'i birleştirerek üst üste ekleyin:

func MainHandler(request string) string {
    return "Response to: " + request
}

handler := LoggingMiddleware(AuthMiddleware(MainHandler))
fmt.Println(handler("GET /users"))
// Output: [LOG] [AUTH] Response to: GET /users

En dıştaki middleware ilk olarak çalışır ve yürütme sırasını belirler. Her middleware, sarmalanmış işleyiciyi çağırmadan önce veya sonra davranış ekleyebilir.

Kendin dene

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Middleware katmanlarının sayısını oku
	nLine, _ := reader.ReadString('\n')
	n, _ := strconv.Atoi(strings.TrimSpace(nLine))

	// Middleware türlerini oku
	middlewareTypes := make([]string, n)
	for i := 0; i < n; i++ {
		line, _ := reader.ReadString('\n')
		middlewareTypes[i] = strings.TrimSpace(line)
	}

	// İsteği oku
	request, _ := reader.ReadString('\n')
	request = strings.TrimSpace(request)

	// TODO: BaseHandler ile başla

	// TODO: İşleyiciyi middleware ile sarmalayarak işlem hattını (pipeline) oluştur
	// Middleware'leri sırayla uygula - okunan ilk middleware en dıştaki sarmalayıcı olur
	// İpucu: Bunu başarmak için middlewareTypes üzerinde TERS sırada döngü kurun
	// Uygulanan son middleware en dıştaki olacaktır (ilk çalışır)

	// TODO: İsteği oluşturulan işleyici aracılığıyla işle ve sonucu yazdır
	fmt.Println("TODO: implement pipeline")
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler