Go dla początkujących - Część 11: Routing Gorilla Mux
Mateusz Kędziora

Jeśli dopiero zaczynasz swoją przygodę z Go, to trafiłeś idealnie. W tym artykule skupimy się na jednym z kluczowych aspektów tworzenia aplikacji internetowych: routingu. Routing to proces, który pozwala skierować przychodzące żądania HTTP do odpowiednich funkcji (tzw. handlerów), które obsłużą to żądanie.
Wyobraź sobie, że piszesz sklep internetowy. Gdy użytkownik wejdzie na adres /produkty
, chcesz wyświetlić listę produktów. Gdy wejdzie na /produkty/123
, chcesz wyświetlić szczegóły produktu o ID 123. Routing pozwala ci zdefiniować, która funkcja w twoim kodzie odpowiada za obsługę każdego z tych adresów.
W Go można to zrobić na kilka sposobów. Zaczniemy od prostego przykładu z użyciem wbudowanej biblioteki net/http
, a następnie przejdziemy do bardziej zaawansowanej i popularnej biblioteki Gorilla Mux
.
Podstawowy routing z net/http
Go posiada wbudowaną bibliotekę net/http
, która oferuje podstawowe narzędzia do obsługi żądań HTTP. Oto jak można zdefiniować prosty routing:
package main
import (
"fmt"
"net/http"
)
// Handler dla strony głównej
func homeHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Witaj na stronie głównej!")
}
// Handler dla strony o produktach
func productsHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Lista produktów!")
}
func main() {
// Rejestrujemy handlery dla konkretnych ścieżek
http.HandleFunc("/", homeHandler) // Obsługuje żądania na adres "/"
http.HandleFunc("/produkty", productsHandler) // Obsługuje żądania na adres "/produkty"
// Uruchamiamy serwer na porcie 8080
fmt.Println("Serwer uruchomiony na porcie 8080")
http.ListenAndServe(":8080", nil) // Drugi argument to handler, nil oznacza użycie defaultServeMux
}
Wyjaśnienie kodu:
package main
: Definiuje pakiet główny.import
: Importuje pakietyfmt
(do formatowania tekstu) inet/http
(do obsługi HTTP).homeHandler(w http.ResponseWriter, r *http.Request)
: To funkcja obsługująca żądania do strony głównej (/
).w http.ResponseWriter
: Odpowiada za wysyłanie odpowiedzi do klienta (przeglądarki).r *http.Request
: Zawiera informacje o żądaniu, takie jak adres URL, nagłówki, etc.fmt.Fprintln(w, "Witaj na stronie głównej!")
: Wysyła tekst “Witaj na stronie głównej!” jako odpowiedź.
productsHandler(w http.ResponseWriter, r *http.Request)
: Funkcja obsługująca żądania do strony produktów (/produkty
).http.HandleFunc(path string, handler func(http.ResponseWriter, *http.Request))
: Rejestruje funkcjęhandler
do obsługi żądań na ścieżcepath
."/"
: Ścieżka dla strony głównej."/produkty"
: Ścieżka dla strony z listą produktów.
http.ListenAndServe(addr string, handler http.Handler)
: Uruchamia serwer HTTP.":8080"
: Adres i port, na którym serwer będzie nasłuchiwał.nil
: Używa domyślnego routera (defaultServeMux).
Uruchom ten kod (zapisz go jako main.go
i użyj go run main.go
) i otwórz w przeglądarce adresy http://localhost:8080/
i http://localhost:8080/produkty
. Powinieneś zobaczyć odpowiednie komunikaty.
Ograniczenia net/http
:
Podstawowy routing z net/http
jest prosty, ale ma kilka ograniczeń:
- Brak obsługi parametrów URL: Trudno jest obsłużyć dynamiczne adresy URL, takie jak
/produkty/123
, gdzie123
jest ID produktu. Trzeba by ręcznie parsować URL. - Brak wsparcia dla różnych metod HTTP: Trudno jest rozróżnić żądania GET, POST, PUT, DELETE dla tej samej ścieżki.
- Brak wsparcia dla middleware: Trudno jest dodać funkcje, które wykonują się przed i po obsłudze każdego żądania (np. logowanie, autentykacja).
- Prosty routing: Dla bardziej złożonych aplikacji routing staje się trudny do zarządzania.
Dlatego właśnie potrzebujemy bardziej zaawansowanej biblioteki do routingu.
Gorilla Mux: Potężny routing dla Go
Gorilla Mux
to popularna biblioteka routingowa dla Go, która rozwiązuje powyższe problemy i oferuje wiele dodatkowych funkcji. Aby jej użyć, musisz ją zainstalować:
go get -u github.com/gorilla/mux
Oto przykład użycia Gorilla Mux
:
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
// Handler dla strony głównej
func homeHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Witaj na stronie głównej!")
}
// Handler dla strony o produkcie (z ID)
func productHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) // Pobieramy parametry z URL
productID := vars["id"] // Odczytujemy parametr "id"
fmt.Fprintf(w, "Szczegóły produktu o ID: %s\n", productID)
}
func main() {
// Tworzymy nowy router
r := mux.NewRouter()
// Definiujemy trasy
r.HandleFunc("/", homeHandler)
r.HandleFunc("/produkty/{id}", productHandler) // {id} to parametr URL
// Uruchamiamy serwer
fmt.Println("Serwer uruchomiony na porcie 8080")
http.ListenAndServe(":8080", r) // Podajemy nasz router jako handler
}
Wyjaśnienie kodu:
import "github.com/gorilla/mux"
: Importuje bibliotekęGorilla Mux
.r := mux.NewRouter()
: Tworzy nowy routerGorilla Mux
.r.HandleFunc("/", homeHandler)
: Rejestruje handlerhomeHandler
dla ścieżki/
. Działa tak samo, jak wnet/http
.r.HandleFunc("/produkty/{id}", productHandler)
: Rejestruje handlerproductHandler
dla ścieżki/produkty/{id}
.{id}
jest tutaj parametrem URL. Oznacza to, że wszystko, co znajdzie się w miejscu{id}
w adresie URL, zostanie przechwycone jako parametr o nazwie “id”.vars := mux.Vars(r)
: Pobiera mapę parametrów URL z żądania.productID := vars["id"]
: Odczytuje wartość parametru “id” z mapyvars
.fmt.Fprintf(w, "Szczegóły produktu o ID: %s\n", productID)
: Wyświetla szczegóły produktu z podanym ID.http.ListenAndServe(":8080", r)
: Uruchamia serwer, przekazując nasz routerr
jako handler. To kluczowe, ponieważ chcemy, abyGorilla Mux
zarządzało routingiem.
Uruchom ten kod i spróbuj wejść na adresy http://localhost:8080/
i http://localhost:8080/produkty/123
. Powinieneś zobaczyć szczegóły produktu o ID 123. Zauważ, że możesz zmienić liczbę po /produkty/
i zobaczysz, że handler automatycznie przechwytuje ten parametr.
Obsługa różnych metod HTTP
Gorilla Mux
pozwala łatwo rozróżnić żądania GET, POST, PUT, DELETE i inne. Możesz to zrobić używając metody Methods()
:
r.HandleFunc("/produkty", createProductHandler).Methods("POST")
r.HandleFunc("/produkty/{id}", getProductHandler).Methods("GET")
r.HandleFunc("/produkty/{id}", updateProductHandler).Methods("PUT")
r.HandleFunc("/produkty/{id}", deleteProductHandler).Methods("DELETE")
W tym przykładzie:
createProductHandler
będzie wywoływany tylko dla żądań POST na adres/produkty
.getProductHandler
będzie wywoływany tylko dla żądań GET na adres/produkty/{id}
.updateProductHandler
będzie wywoływany tylko dla żądań PUT na adres/produkty/{id}
.deleteProductHandler
będzie wywoływany tylko dla żądań DELETE na adres/produkty/{id}
.
To bardzo przydatne przy tworzeniu API RESTful.
Middleware w Gorilla Mux
Middleware to funkcje, które wykonują się przed i/lub po handlerze. Można ich użyć do różnych celów, takich jak:
- Logowanie żądań
- Uwierzytelnianie użytkowników
- Sprawdzanie uprawnień
- Dodawanie nagłówków HTTP
Oto jak można zdefiniować prosty middleware w Gorilla Mux
:
// Middleware do logowania żądań
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Wykonujemy kod przed handlerem
fmt.Println("Odebrano żądanie:", r.URL.Path)
// Wywołujemy następny handler w łańcuchu
next.ServeHTTP(w, r)
// Wykonujemy kod po handlerze (opcjonalne)
})
}
Wyjaśnienie kodu:
loggingMiddleware(next http.Handler) http.Handler
: Funkcja middleware przyjmujehttp.Handler
(następny handler w łańcuchu) jako argument i zwraca nowyhttp.Handler
.http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ... })
: Tworzy nowy handler z anonimowej funkcji.fmt.Println("Odebrano żądanie:", r.URL.Path)
: Loguje ścieżkę URL żądania.next.ServeHTTP(w, r)
: Wywołuje następny handler w łańcuchu. To kluczowe, aby żądanie zostało obsłużone.
Aby użyć tego middleware, musisz go dodać do routera:
r := mux.NewRouter()
r.Use(loggingMiddleware) // Dodajemy middleware do routera
Teraz każde żądanie, które zostanie obsłużone przez ten router, zostanie najpierw “przechwycone” przez loggingMiddleware
, które wypisze ścieżkę URL do konsoli.
Można łączyć wiele middleware, tworząc łańcuch. Kolejność middleware ma znaczenie, ponieważ są one wykonywane w kolejności, w jakiej zostały dodane.
Subroutery
Subroutery pozwalają na grupowanie tras pod wspólnym prefiksem. Jest to przydatne do tworzenia bardziej zorganizowanych aplikacji.
Oto przykład:
s := r.PathPrefix("/api/v1").Subrouter() // Tworzymy subrouter z prefiksem "/api/v1"
s.HandleFunc("/produkty", listProductsHandler).Methods("GET")
s.HandleFunc("/produkty/{id}", getProductHandler).Methods("GET")
W tym przykładzie:
r.PathPrefix("/api/v1").Subrouter()
: Tworzy subrouter, który obsługuje tylko żądania, których ścieżka zaczyna się od/api/v1
.s.HandleFunc("/produkty", listProductsHandler).Methods("GET")
: Rejestruje handler dla ścieżki/api/v1/produkty
(zwróć uwagę na prefiks).s.HandleFunc("/produkty/{id}", getProductHandler).Methods("GET")
: Rejestruje handler dla ścieżki/api/v1/produkty/{id}
(zwróć uwagę na prefiks).
Subroutery mogą również mieć własne middleware. Dzięki temu możesz dodać middleware, które będą dotyczyły tylko określonej grupy tras.
Inne funkcje Gorilla Mux
Gorilla Mux oferuje wiele innych przydatnych funkcji, takich jak:
- Regexp Route Matching: Możesz używać wyrażeń regularnych do dopasowywania adresów URL.
- Custom Matchers: Możesz tworzyć własne matchery do dopasowywania tras na podstawie dowolnych kryteriów.
- URL Building: Możesz generować adresy URL na podstawie nazw tras i parametrów.
Zachęcam do zapoznania się z dokumentacją Gorilla Mux
, aby dowiedzieć się więcej o tych funkcjach: https://github.com/gorilla/mux
Porównanie net/http
i Gorilla Mux
Funkcja | net/http | Gorilla Mux |
---|---|---|
Parametry URL | Brak wbudowanej obsługi | Wbudowana obsługa z użyciem {parametr} |
Metody HTTP | Ograniczone wsparcie | Pełne wsparcie z Methods() |
Middleware | Brak wbudowanego wsparcia | Wbudowane wsparcie z Use() |
Subroutery | Brak wbudowanego wsparcia | Wbudowane wsparcie z PathPrefix().Subrouter() |
Routing złożony | Trudny do zarządzania | Łatwy do zarządzania |
Złożoność projektu | Wystarczający dla małych projektów | Zalecany dla większych projektów |
Podsumowując, net/http
jest dobry do prostych aplikacji, ale Gorilla Mux
jest zdecydowanie lepszym wyborem dla bardziej złożonych aplikacji, które wymagają parametrów URL, różnych metod HTTP, middleware i subrouterów.
Praca domowa
Stwórz prosty API RESTful dla książek.
- Użyj
Gorilla Mux
. - Zdefiniuj trasy dla:
- GET
/books
- Pobranie listy wszystkich książek. - POST
/books
- Dodanie nowej książki. - GET
/books/{id}
- Pobranie książki o danym ID. - PUT
/books/{id}
- Aktualizacja książki o danym ID. - DELETE
/books/{id}
- Usunięcie książki o danym ID.
- GET
- Użyj prostych struktur danych w pamięci (np. slice) do przechowywania książek. Nie musisz łączyć się z bazą danych.
- Dodaj middleware do logowania każdego żądania (ścieżka URL i metoda HTTP).
- Użyj
Dodaj uwierzytelnianie do API.
- Dodaj middleware, który sprawdza nagłówek
Authorization
. - Jeśli nagłówek
Authorization
jest poprawny (np. zawiera poprawne hasło API), zezwól na dostęp do zasobów. - W przeciwnym razie zwróć błąd 401 Unauthorized.
- Dodaj middleware, który sprawdza nagłówek
To ćwiczenie pomoże Ci utrwalić wiedzę na temat routingu, parametrów URL, metod HTTP i middleware w Gorilla Mux
.
Podsumowanie
W tym artykule omówiliśmy routing w Go, zaczynając od podstawowej biblioteki net/http
, a następnie przechodząc do bardziej zaawansowanej biblioteki Gorilla Mux
. Nauczyliśmy się definiować trasy, obsługiwać parametry URL, middleware i subroutery.
Gorilla Mux
to potężne narzędzie, które znacznie ułatwia tworzenie aplikacji internetowych w Go. Zachęcam do eksperymentowania z różnymi funkcjami Gorilla Mux
i do dalszego zgłębiania wiedzy na temat Go.
Przydatne linki
- Oficjalna dokumentacja Go: https://go.dev/
- Dokumentacja pakietu
net/http
: https://pkg.go.dev/net/http - Dokumentacja
Gorilla Mux
: https://github.com/gorilla/mux - A Tour of Go: https://go.dev/tour/welcome/1
- Effective Go: https://go.dev/doc/effective_go
Pamiętaj, że nauka programowania to proces ciągłego uczenia się i eksperymentowania. Nie bój się próbować nowych rzeczy i zadawać pytania. Powodzenia! I koniecznie sprawdź inne artykuły na moim blogu, aby pogłębić swoją wiedzę o Go!
Polecane artykuły
Docker vs Kubernetes: Który dla Ciebie w 2025?
Docker i Kubernetes objaśnione! Która technologia lepsza dla początkujących w 2025? Porównanie, przykłady i przyszłość.
Mateusz Kędziora
DevOps: Automatyzacja zadań sysadmina dla programistów
Zautomatyzuj pracę sysadmina w środowisku DevOps! Praktyczne przykłady, skrypty, Ansible, Terraform, Prometheus i Grafana.
Mateusz Kędziora
Automatyzacja Linux/macOS z Bash: Praktyczny Przewodnik
Zacznij automatyzować system Linux/macOS z Bash! Dowiedz się, czym jest Bash, jak pisać skrypty i używać podstawowych komend.
Mateusz Kędziora