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'da Dekoratör kalıbının en pratik uygulamalarından biridir. Web geliştirmede middleware işlevleri, özgün işleyiciyi değiştirmeden günlük kaydı, kimlik doğrulama veya zamanlama gibi kesişen konular eklemek için HTTP işleyicilerini sarar.

Temel fikir, ara yazılımın bir işleyici alıp eklenmiş davranışa sahip yeni bir işleyici döndürmesidir. Bu, Decorator desenini tam olarak izler: girişte ve çıkışta aynı arayüz, geliştirilmiş işlevsellikle birlikte:

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 yazılım, zincirdeki bir sonraki işleyiciyi sarar ve sarılmış işleyiciyi çağırmadan önce veya çağırdıktan sonra kendi davranışını ekler. Birden fazla ara yazılımı birleştirerek ü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

Sarmalama sırası, yürütme sırasını belirler: en dıştaki ara yazılım ilk olarak çalışır. Bu desen, istek işleme işlem hatları için Go web çatılarında yaygın olarak kullanılır ve temel işleyici mantığına dokunmadan işlevsellik eklemeyi veya kaldırmayı kolaylaştırır.

challenge icon

Görev

Kolay

Middleware as Decorator desenini kullanarak bir istek işleme hattı oluşturalım! Middleware işlevlerinin, temel işleyici mantığını değiştirmeden zamanlama, doğrulama ve biçimlendirme gibi işlevler eklemek için işleyicileri sardığı bir sistem oluşturacaksın.

Kodunu üç dosya arasında düzenleyeceksin:

  • handler.go: İşleyici türünü ve istekleri işleyen temel işleyiciyi tanımla.

    Bir istek dizesi alan ve bir yanıt dizesi döndüren bir işlev olarak Handler türü oluştur:

    type Handler func(request string) string

    Aldığı her istek için BaseHandler döndüren bir Processed: [request] işlevi uygula.

  • middleware.go: İşleyicileri ek davranışlarla saran middleware işlevlerini oluştur.

    Her biri bir Handler alan ve yeni bir Handler döndüren üç middleware işlevi oluştur:

    • TimingMiddleware: yanıta zamanlama bilgisi ekleyerek [TIMING] [response] döndürür
    • ValidationMiddleware: doğrulama öneki ekleyerek [VALID] [response] döndürür
    • UppercaseMiddleware: yanıtın tamamını büyük harfe dönüştürür

    Her middleware, sardığı işleyiciyi çağırmalı ve sonucunu geliştirmelidir.

  • main.go: Middleware'leri birleştirerek bir işleme hattı oluştur.

    Uygulanacak middleware katmanlarının sayısını oku. Ardından her katman için middleware türünü (timing, validation veya uppercase) oku ve mevcut işleyicini bu middleware ile sar. Middleware'leri okundukları sırayla uygula: okunan ilk middleware en dıştaki sarmalayıcı olur.

    İşleme hattını oluşturduktan sonra istek dizesini oku, oluşturduğun işleyici üzerinden işle ve sonucu yazdır.

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

  • 1. satır: Middleware katmanlarının sayısı
  • Sonraki satırlar: Her satırda bir middleware türü (timing, validation veya uppercase)
  • Son satır: İşlenecek istek

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

2
timing
validation
GET /users

Çıktın şöyle olmalıdır:

[TIMING] [VALID] Processed: GET /users

Ve şu giriş verildiğinde:

3
uppercase
timing
validation
POST /data

Çıktın şöyle olmalıdır:

[TIMING] [VALID] PROCESSED: POST /DATA

Ve şu giriş verildiğinde:

1
uppercase
hello world

Çıktın şöyle olmalıdır:

PROCESSED: HELLO WORLD

Ve şu giriş verildiğinde:

0
simple request

Çıktın şöyle olmalıdır:

Processed: simple request

Middleware sarmalama sırasının çıktıyı nasıl etkilediğine dikkat et: uygulanan ilk middleware (en dıştaki) önce çalışır ve tüm iç middleware'lerden gelen nihai sonucu görür. İkinci örnekteki uppercase middleware'i en son (en içte) çalışır; bu nedenle timing ve validation öneklerini eklemeden önce temel yanıtı büyük harfe dönüştürür!

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: Handler'ı middleware ile sararak pipeline'ı oluştur
	// Middleware'leri sırayla uygula - okunan ilk middleware en dış sarmalayıcı olur
	// İpucu: Bunu başarmak için middlewareTypes üzerinde TERS sırada döngü yap
	// Uygulanan son middleware en dıştaki olacaktır (ilk çalışır)

	// TODO: İsteği birleştirilmiş handler üzerinden 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

Kendi başına pratik yap: Online Go derleyicisi