接口开发

RESTful API设计

使用Go实现RESTful API的最佳实践。

package main

import (
    "encoding/json"
    "net/http"
    "github.com/gorilla/mux"
)

type User struct {
    ID       string `json:"id"`
    Name     string `json:"name"`
    Email    string `json:"email"`
    Password string `json:"-"` // 不在JSON中显示
}

// 创建用户
func createUser(w http.ResponseWriter, r *http.Request) {
    var user User
    if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    // 处理用户创建...
    
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(user)
}

// 获取用户列表
func getUsers(w http.ResponseWriter, r *http.Request) {
    users := []User{
        {ID: "1", Name: "John", Email: "john@example.com"},
        {ID: "2", Name: "Jane", Email: "jane@example.com"},
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(users)
}

// 获取单个用户
func getUser(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    id := vars["id"]
    
    // 查找用户...
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(User{ID: id, Name: "John", Email: "john@example.com"})
}

// 更新用户
func updateUser(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    id := vars["id"]
    
    var user User
    if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    user.ID = id
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(user)
}

// 删除用户
func deleteUser(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    id := vars["id"]
    
    // 删除用户...
    
    w.WriteHeader(http.StatusNoContent)
}

func main() {
    r := mux.NewRouter()
    
    // 注册路由
    r.HandleFunc("/users", createUser).Methods("POST")
    r.HandleFunc("/users", getUsers).Methods("GET")
    r.HandleFunc("/users/{id}", getUser).Methods("GET")
    r.HandleFunc("/users/{id}", updateUser).Methods("PUT")
    r.HandleFunc("/users/{id}", deleteUser).Methods("DELETE")
    
    http.ListenAndServe(":8080", r)
}

API版本控制

实现API版本控制的最佳实践。

package main

import (
    "net/http"
    "github.com/gorilla/mux"
)

func v1Handler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("API v1"))
}

func v2Handler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("API v2"))
}

func main() {
    r := mux.NewRouter()
    
    // 版本1路由
    v1 := r.PathPrefix("/v1").Subrouter()
    v1.HandleFunc("/users", v1Handler)
    
    // 版本2路由
    v2 := r.PathPrefix("/v2").Subrouter()
    v2.HandleFunc("/users", v2Handler)
    
    http.ListenAndServe(":8080", r)
}

API文档

使用Swagger生成API文档。

package main

import (
    "github.com/swaggo/http-swagger"
    "github.com/swaggo/swag"
)

// @title User API
// @version 1.0
// @description This is a sample user API
// @host localhost:8080
// @BasePath /api/v1

// @tag.name Users
// @tag.description User management operations

// @route POST /users
// @summary Create a new user
// @description Create a new user with the provided information
// @tags Users
// @accept json
// @produce json
// @param user body User true "User object"
// @success 201 {object} User
// @failure 400 {object} ErrorResponse
// @router /users [post]
func createUser(w http.ResponseWriter, r *http.Request) {
    // 实现代码...
}

func main() {
    r := mux.NewRouter()
    
    // 注册Swagger文档
    r.PathPrefix("/swagger/").Handler(httpSwagger.WrapHandler)
    
    http.ListenAndServe(":8080", r)
}

API认证

实现API认证和授权。

package main

import (
    "net/http"
    "github.com/dgrijalva/jwt-go"
)

type Claims struct {
    UserID string `json:"user_id"`
    jwt.StandardClaims
}

func generateToken(userID string) (string, error) {
    claims := &Claims{
        UserID: userID,
        StandardClaims: jwt.StandardClaims{
            ExpiresAt: time.Now().Add(24 * time.Hour).Unix(),
        },
    }
    
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString([]byte("your-secret-key"))
}

func authMiddleware(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        tokenString := r.Header.Get("Authorization")
        if tokenString == "" {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        
        claims := &Claims{}
        token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
            return []byte("your-secret-key"), nil
        })
        
        if err != nil || !token.Valid {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        
        next.ServeHTTP(w, r)
    }
}

func main() {
    http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
        // 处理登录...
        token, _ := generateToken("user123")
        w.Write([]byte(token))
    })
    
    http.HandleFunc("/protected", authMiddleware(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Protected resource"))
    }))
    
    http.ListenAndServe(":8080", nil)
}

API限流

实现API请求限流。

package main

import (
    "net/http"
    "sync"
    "time"
)

type RateLimiter struct {
    requests map[string][]time.Time
    mu       sync.Mutex
    limit    int
    window   time.Duration
}

func NewRateLimiter(limit int, window time.Duration) *RateLimiter {
    return &RateLimiter{
        requests: make(map[string][]time.Time),
        limit:    limit,
        window:   window,
    }
}

func (rl *RateLimiter) Allow(ip string) bool {
    rl.mu.Lock()
    defer rl.mu.Unlock()
    
    now := time.Now()
    windowStart := now.Add(-rl.window)
    
    // 清理过期的请求记录
    validRequests := make([]time.Time, 0)
    for _, t := range rl.requests[ip] {
        if t.After(windowStart) {
            validRequests = append(validRequests, t)
        }
    }
    
    if len(validRequests) >= rl.limit {
        return false
    }
    
    validRequests = append(validRequests, now)
    rl.requests[ip] = validRequests
    return true
}

func rateLimitMiddleware(limiter *RateLimiter) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            ip := r.RemoteAddr
            if !limiter.Allow(ip) {
                http.Error(w, "Too many requests", http.StatusTooManyRequests)
                return
            }
            next.ServeHTTP(w, r)
        })
    }
}

func main() {
    limiter := NewRateLimiter(100, time.Minute)
    
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, World!"))
    })
    
    handler := rateLimitMiddleware(limiter)(mux)
    http.ListenAndServe(":8080", handler)
}