Go의 동시성 패턴을 익혔다면, 이제 실제 웹 서버를 구축할 차례입니다.
표준 라이브러리 net/http만으로도 강력한 REST API를 만들 수 있습니다.
After learning Go's concurrency patterns, it's time to build real web servers.
You can create powerful REST APIs using just the standard library net/http.
기본 HTTP 서버 Basic HTTP Server
package main
import (
"fmt"
"net/http"
)
func main() {
// 핸들러 등록
http.HandleFunc("/hello", helloHandler)
http.HandleFunc("/api/users", usersHandler)
// 서버 시작
fmt.Println("Server starting on :8080")
http.ListenAndServe(":8080", nil)
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}
import (
"fmt"
"net/http"
)
func main() {
// 핸들러 등록
http.HandleFunc("/hello", helloHandler)
http.HandleFunc("/api/users", usersHandler)
// 서버 시작
fmt.Println("Server starting on :8080")
http.ListenAndServe(":8080", nil)
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}
package main
import (
"fmt"
"net/http"
)
func main() {
// Register handlers
http.HandleFunc("/hello", helloHandler)
http.HandleFunc("/api/users", usersHandler)
// Start server
fmt.Println("Server starting on :8080")
http.ListenAndServe(":8080", nil)
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}
import (
"fmt"
"net/http"
)
func main() {
// Register handlers
http.HandleFunc("/hello", helloHandler)
http.HandleFunc("/api/users", usersHandler)
// Start server
fmt.Println("Server starting on :8080")
http.ListenAndServe(":8080", nil)
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}
JSON API 핸들러 JSON API Handler
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func usersHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
users := []User{{1, "Kim", "[email protected]"}}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
case http.MethodPost:
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func usersHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
users := []User{{1, "Kim", "[email protected]"}}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
case http.MethodPost:
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func usersHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
users := []User{{1, "Kim", "[email protected]"}}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
case http.MethodPost:
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func usersHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
users := []User{{1, "Kim", "[email protected]"}}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
case http.MethodPost:
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
미들웨어 패턴 Middleware Pattern
미들웨어는 핸들러를 감싸서 로깅, 인증, CORS 등 공통 기능을 처리합니다.
Middleware wraps handlers to handle common functionality like logging, authentication, and CORS.
// 로깅 미들웨어
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
})
}
// CORS 미들웨어
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
next.ServeHTTP(w, r)
})
}
// 미들웨어 체이닝
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/api/users", usersHandler)
handler := loggingMiddleware(corsMiddleware(mux))
http.ListenAndServe(":8080", handler)
}
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
})
}
// CORS 미들웨어
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
next.ServeHTTP(w, r)
})
}
// 미들웨어 체이닝
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/api/users", usersHandler)
handler := loggingMiddleware(corsMiddleware(mux))
http.ListenAndServe(":8080", handler)
}
// Logging middleware
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
})
}
// CORS middleware
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
next.ServeHTTP(w, r)
})
}
// Middleware chaining
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/api/users", usersHandler)
handler := loggingMiddleware(corsMiddleware(mux))
http.ListenAndServe(":8080", handler)
}
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
})
}
// CORS middleware
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
next.ServeHTTP(w, r)
})
}
// Middleware chaining
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/api/users", usersHandler)
handler := loggingMiddleware(corsMiddleware(mux))
http.ListenAndServe(":8080", handler)
}
Graceful Shutdown Graceful Shutdown
func main() {
srv := &http.Server{
Addr: ":8080",
Handler: mux,
}
// 시그널 채널
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
go func() {
log.Println("Server starting...")
srv.ListenAndServe()
}()
<-quit
log.Println("Shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
srv.Shutdown(ctx)
}
srv := &http.Server{
Addr: ":8080",
Handler: mux,
}
// 시그널 채널
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
go func() {
log.Println("Server starting...")
srv.ListenAndServe()
}()
<-quit
log.Println("Shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
srv.Shutdown(ctx)
}
func main() {
srv := &http.Server{
Addr: ":8080",
Handler: mux,
}
// Signal channel
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
go func() {
log.Println("Server starting...")
srv.ListenAndServe()
}()
<-quit
log.Println("Shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
srv.Shutdown(ctx)
}
srv := &http.Server{
Addr: ":8080",
Handler: mux,
}
// Signal channel
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
go func() {
log.Println("Server starting...")
srv.ListenAndServe()
}()
<-quit
log.Println("Shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
srv.Shutdown(ctx)
}
💡 인기 Go 웹 프레임워크 💡 Popular Go Web Frameworks
- Gin: 빠르고 간단한 라우팅
- Gin: Fast and simple routing
- Echo: 성능과 확장성
- Echo: Performance and extensibility
- Fiber: Express.js 스타일
- Fiber: Express.js style
