Eine Web-API ermöglicht es, Daten und Funktionen über das HTTP-Protokoll verfügbar zu machen. RESTful-APIs (Representational State Transfer) sind eine weit verbreitete Methode zur Implementierung von Web-APIs.
net/httpBeginnen wir mit der Erstellung einer einfachen HTTP-API, die grundlegende CRUD-Operationen (Create, Read, Update, Delete) unterstützt:
package main
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"sync"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
var (
users = []User{}
nextID = 1
mu sync.Mutex
)
func getUsers(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
func createUser(w http.ResponseWriter, r *http.Request) {
var user User
json.NewDecoder(r.Body).Decode(&user)
mu.Lock()
user.ID = nextID
nextID++
users = append(users, user)
mu.Unlock()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
}
func getUser(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(r.URL.Query().Get("id"))
mu.Lock()
defer mu.Unlock()
for _, user := range users {
if user.ID == id {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
return
}
}
http.NotFound(w, r)
}
func updateUser(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(r.URL.Query().Get("id"))
var updatedUser User
json.NewDecoder(r.Body).Decode(&updatedUser)
mu.Lock()
defer mu.Unlock()
for i, user := range users {
if user.ID == id {
users[i].Name = updatedUser.Name
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users[i])
return
}
}
http.NotFound(w, r)
}
func deleteUser(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(r.URL.Query().Get("id"))
mu.Lock()
defer mu.Unlock()
for i, user := range users {
if user.ID == id {
users = append(users[:i], users[i+1:]...)
w.WriteHeader(http.StatusNoContent)
return
}
}
http.NotFound(w, r)
}
func main() {
http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
getUsers(w, r)
} else if r.Method == http.MethodPost {
createUser(w, r)
}
})
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
getUser(w, r)
} else if r.Method == http.MethodPut {
updateUser(w, r)
} else if r.Method == http.MethodDelete {
deleteUser(w, r)
}
})
fmt.Println("Server started at :8080")
http.ListenAndServe(":8080", nil)
}In diesem Beispiel:
User-Typ mit den Feldern
ID und Name./users und
/user und starten den HTTP-Server.Um eine robuste API zu erstellen, müssen wir Eingaben validieren und Fehler korrekt behandeln:
func createUser(w http.ResponseWriter, r *http.Request) {
var user User
err := json.NewDecoder(r.Body).Decode(&user)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if user.Name == "" {
http.Error(w, "Name is required", http.StatusBadRequest)
return
}
mu.Lock()
user.ID = nextID
nextID++
users = append(users, user)
mu.Unlock()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
}Middleware ist eine Technik, um wiederverwendbare Funktionen wie Logging, Authentifizierung oder CORS-Handling zu implementieren:
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
})
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
getUsers(w, r)
} else if r.Method == http.MethodPost {
createUser(w, r)
}
})
mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
getUser(w, r)
} else if r.Method == http.MethodPut {
updateUser(w, r)
} else if r.Method == http.MethodDelete {
deleteUser(w, r)
}
})
loggedMux := loggingMiddleware(mux)
fmt.Println("Server started at :8080")
http.ListenAndServe(":8080", loggedMux)
}In diesem Beispiel verwenden wir eine Logging-Middleware, die alle eingehenden Anfragen protokolliert.