REST API's bouwen in Go: Compleet gids
Maak productiebereide REST-Api's met Go's robuuste ecosystem
Het bouwen van hoge-prestaties REST API’s met Go is geworden een standaard aanpak voor het aandrijven van systemen bij Google, Uber, Dropbox en talloze startups.
De eenvoud van Go, de sterke ondersteuning voor concurrentie en de snelle compilatie maken het ideaal voor microservices en backendontwikkeling.
Deze geweldige afbeelding wordt gegenereerd door FLUX.1-Kontext-dev: Image Augmentation AI Model.
Waarom Go voor API-ontwikkeling?
Go biedt verschillende overtuigende voordelen voor API-ontwikkeling:
Prestaties en efficiëntie: Go compileert naar native machinecode, wat bijna C-prestaties oplevert zonder de complexiteit. De efficiënte geheugentoevoeging en kleine bestandsgroottes maken het perfect voor containerimplementaties.
Ingebouwde concurrentie: Goroutines en kanalen maken het gemakkelijk om duizenden gelijktijdige verzoeken te verwerken. Je kunt meerdere API-aanvragen tegelijk verwerken zonder complexe draadcode.
Sterke standaardbibliotheek: Het net/http-pakket biedt een productieve HTTP-server uit de doos. Je kunt volledige API’s bouwen zonder enige externe afhankelijkheden.
Snelle compilatie: De compilatiesnelheid van Go biedt snelle iteratie tijdens de ontwikkeling. Grote projecten compileren in seconden, niet in minuten.
Statistische typen met eenvoud: Het type-systeem van Go vangt fouten tijdens de compilatie terwijl het de codehelderheid behoudt. De taal heeft een klein aantal functies dat snel te leren is.
Aanpakken voor het bouwen van API’s in Go
Gebruik van de standaardbibliotheek
De standaardbibliotheek van Go biedt alles wat nodig is voor basis API-ontwikkeling. Hier is een minimale voorbeeld:
package main
import (
"encoding/json"
"log"
"net/http"
)
type Response struct {
Message string `json:"message"`
Status int `json:"status"`
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(Response{
Message: "API is healthy",
Status: 200,
})
}
func main() {
http.HandleFunc("/health", healthHandler)
log.Println("Server starting on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Deze aanpak biedt volledige controle en nul afhankelijkheden. Het is ideaal voor eenvoudige API’s of wanneer je HTTP-verwerking op een fundamentele niveau wilt begrijpen.
Populaire Go-webframeworks
Hoewel de standaardbibliotheek krachtig is, kunnen frameworks de ontwikkeling versnellen:
Gin: Het populairste Go-webframework, bekend om zijn prestaties en gebruiksgemak. Het biedt handige routing, ondersteuning voor middleware en aanvraagvalidatie.
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/users/:id", func(c *gin.Context) {
id := c.Param("id")
c.JSON(http.StatusOK, gin.H{
"user_id": id,
"name": "John Doe",
})
})
r.Run(":8080")
}
Chi: Een lichtgewicht, idiomatische router die voelt als een uitbreiding van de standaardbibliotheek. Het is vooral geschikt voor het bouwen van RESTful services met geneste routing.
Echo: Een hoge-prestaties framework met uitgebreide middleware en uitstekende documentatie. Het is geoptimaliseerd voor snelheid terwijl het ontwikkelaarvriendelijk blijft.
Fiber: Geïnspireerd door Express.js, gebouwd op Fasthttp. Het is de snelste optie, maar gebruikt een andere HTTP-implementatie dan de standaardbibliotheek.
Architectuurpatronen
Wanneer je werkt aan databasebewerkingen in Go, moet je je ORM-strategie overwegen. Verschillende projecten hebben benaderingen vergeleken zoals GORM, Ent, Bun, en sqlc, elk met verschillende afwegingen tussen ontwikkelaarsproductiviteit en prestaties.
Laagarchitectuur
Structuur je API met een duidelijke scheiding van zorgen:
// Handlerlaag - HTTP-aangezicht
type UserHandler struct {
service *UserService
}
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
user, err := h.service.GetByID(r.Context(), id)
if err != nil {
respondError(w, err)
return
}
respondJSON(w, user)
}
// Servicelaag - Bedrijfslogica
type UserService struct {
repo *UserRepository
}
func (s *UserService) GetByID(ctx context.Context, id string) (*User, error) {
// Valideer, transformeer, toepas de bedrijfsregels
return s.repo.FindByID(ctx, id)
}
// Repositorylaag - Data toegang
type UserRepository struct {
db *sql.DB
}
func (r *UserRepository) FindByID(ctx context.Context, id string) (*User, error) {
// Implementatie van databasequery
}
Deze scheiding maakt testen gemakkelijker en houdt je code onderhoudbaar terwijl het project groeit.
Domein-gerichte ontwerpen
Voor complexe toepassingen, overweeg het organiseren van code op basis van domein in plaats van technische lagen. Elke domeinpakket bevat zijn eigen modellen, services en repositories.
Als je multi-tenant toepassingen bouwt, wordt het begrijpen van databasepatronen voor multi-tenant cruciaal voor je API-architectuur.
Verzoekverwerking en validatie
Invoervalidatie
Valideer altijd binnenkomende data voorafgaand aan verwerking:
type CreateUserRequest struct {
Email string `json:"email" validate:"required,email"`
Username string `json:"username" validate:"required,min=3,max=50"`
Age int `json:"age" validate:"gte=0,lte=150"`
}
func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
var req CreateUserRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
respondError(w, NewBadRequestError("Ongeldig JSON"))
return
}
validate := validator.New()
if err := validate.Struct(req); err != nil {
respondError(w, NewValidationError(err))
return
}
// Verwerk geldig verzoek
}
Het go-playground/validator-pakket biedt uitgebreide validatieregels en aangepaste validatoren.
Verzoekcontext
Gebruik context voor request-gekoppelde waarden en annulering:
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
userID, err := validateToken(token)
if err != nil {
http.Error(w, "Ongeautoriseerd", http.StatusUnauthorized)
return
}
ctx := context.WithValue(r.Context(), "userID", userID)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
Authenticatie en beveiliging
JWT-gebaseerde authenticatie
JSON Web Tokens bieden stateless authenticatie:
import "github.com/golang-jwt/jwt/v5"
func generateToken(userID string) (string, error) {
claims := jwt.MapClaims{
"user_id": userID,
"exp": time.Now().Add(time.Hour * 24).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(os.Getenv("JWT_SECRET")))
}
func validateToken(tokenString string) (string, error) {
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte(os.Getenv("JWT_SECRET")), nil
})
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
return claims["user_id"].(string), nil
}
return "", err
}
Middlewarepatronen
Implementeer kruisende zorgen als middleware:
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
log.Printf("Gestart %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
log.Printf("Voltooid in %v", time.Since(start))
})
}
func rateLimitMiddleware(next http.Handler) http.Handler {
limiter := rate.NewLimiter(10, 20) // 10 verzoeken/sec, burst van 20
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !limiter.Allow() {
http.Error(w, "Rate limit overschreden", http.StatusTooManyRequests)
return
}
next.ServeHTTP(w, r)
})
}
Foutafhandeling
Implementeer consistente foutreacties:
type APIError struct {
Code int `json:"code"`
Message string `json:"message"`
Details string `json:"details,omitempty"`
}
func (e *APIError) Error() string {
return e.Message
}
func NewBadRequestError(message string) *APIError {
return &APIError{
Code: http.StatusBadRequest,
Message: message,
}
}
func NewNotFoundError(resource string) *API错误 {
return &APIError{
Code: http.StatusNotFound,
Message: fmt.Sprintf("%s niet gevonden", resource),
}
}
func respondError(w http.ResponseWriter, err error) {
apiErr, ok := err.(*APIError)
if !ok {
apiErr = &APIError{
Code: http.StatusInternalServerError,
Message: "Interne serverfout",
}
// Log de werkelijke fout voor foutopsporing
log.Printf("Onverwachte fout: %v", err)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(apiErr.Code)
json.NewEncoder(w).Encode(apiErr)
}
Databaseintegratie
Verbindingsbeheer
Gebruik verbindingspooling voor efficiënte toegang tot de database:
func initDB() (*sql.DB, error) {
db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
return nil, err
}
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(5 * time.Minute)
return db, db.Ping()
}
Querypatronen
Gebruik voorbereide statements en context voor veilige databasebewerkingen:
func (r *UserRepository) FindByEmail(ctx context.Context, email string) (*User, error) {
query := `SELECT id, email, username, created_at FROM users WHERE email = $1`
var user User
err := r.db.QueryRowContext(ctx, query, email).Scan(
&user.ID,
&user.Email,
&user.Username,
&user.CreatedAt,
)
if err == sql.ErrNoRows {
return nil, ErrUserNotFound
}
return &user, err
}
Teststrategieën
Handler tests
Test HTTP-handlers met httptest:
func TestGetUserHandler(t *testing.T) {
// Setup
mockService := &MockUserService{
GetByIDFunc: func(ctx context.Context, id string) (*User, error) {
return &User{ID: "1", Username: "testuser"}, nil
},
}
handler := &UserHandler{service: mockService}
// Execute
req := httptest.NewRequest("GET", "/users/1", nil)
w := httptest.NewRecorder()
handler.GetUser(w, req)
// Assert
assert.Equal(t, http.StatusOK, w.Code)
var response User
json.Unmarshal(w.Body.Bytes(), &response)
assert.Equal(t, "testuser", response.Username)
}
Integratiestesten
Test volledige workflows met een testdatabase:
func TestCreateUserEndToEnd(t *testing.T) {
// Setup testdatabase
db := setupTestDB(t)
defer db.Close()
// Start testserver
server := setupTestServer(db)
defer server.Close()
// Make request
body := strings.NewReader(`{"email":"test@example.com","username":"testuser"}`)
resp, err := http.Post(server.URL+"/users", "application/json", body)
require.NoError(t, err)
defer resp.Body.Close()
// Verify response
assert.Equal(t, http.StatusCreated, resp.StatusCode)
// Verify database state
var count int
db.QueryRow("SELECT COUNT(*) FROM users WHERE email = $1", "test@example.com").Scan(&count)
assert.Equal(t, 1, count)
}
API-documentatie
OpenAPI/Swagger
Documenteer je API met OpenAPI-specificaties:
// @title User API
// @version 1.0
// @description API voor het beheren van gebruikers
// @host localhost:8080
// @BasePath /api/v1
// @Summary Gebruiker opzoeken op ID
// @Description Haalt informatie over een gebruiker op met hun ID
// @Tags gebruikers
// @Accept json
// @Produce json
// @Param id path string true "Gebruikers ID"
// @Success 200 {object} User
// @Failure 404 {object} APIError
// @Router /users/{id} [get]
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
// Implementatie
}
Gebruik swaggo/swag om interactieve API-documentatie te genereren vanuit deze opmerkingen.
Prestatiesoptimalisatie
Reactiecompressie
Schakel gzip-compressie in voor reacties:
import "github.com/NYTimes/gziphandler"
func main() {
r := chi.NewRouter()
r.Use(gziphandler.GzipHandler)
// Rest van de instellingen
}
Caching
Implementeer caching voor frequent aangevraagde data:
import "github.com/go-redis/redis/v8"
type CachedUserRepository struct {
repo *UserRepository
cache *redis.Client
}
func (r *CachedUserRepository) GetByID(ctx context.Context, id string) (*User, error) {
// Probeer cache eerst
cached, err := r.cache.Get(ctx, "user:"+id).Result()
if err == nil {
var user User
json.Unmarshal([]byte(cached), &user)
return &user, nil
}
// Cache mislukt - haal op uit database
user, err := r.repo.FindByID(ctx, id)
if err != nil {
return nil, err
}
// Bewaar in cache
data, _ := json.Marshal(user)
r.cache.Set(ctx, "user:"+id, data, 10*time.Minute)
return user, nil
}
Verbindingspooling
Herbruik HTTP-verbindingen voor externe API-aanroepen:
var httpClient = &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
}
Implementatieoverwegingen
Docker-containerisatie
Creëer efficiënte Docker-afbeeldingen met meerdere stappen:
# Bouwstap
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o api ./cmd/api
# Productiestap
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/api .
EXPOSE 8080
CMD ["./api"]
Dit produceert een minimale afbeelding (meestal onder 20MB) met alleen je binaire bestand en essentiële certificaten.
Configuratiebeheer
Gebruik omgevingsvariabelen en configuratiebestanden:
type Config struct {
Port string
DatabaseURL string
JWTSecret string
LogLevel string
}
func LoadConfig() (*Config, error) {
return &Config{
Port: getEnv("PORT", "8080"),
DatabaseURL: getEnv("DATABASE_URL", ""),
JWTSecret: getEnv("JWT_SECRET", ""),
LogLevel: getEnv("LOG_LEVEL", "info"),
}, nil
}
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
Vreedzame afsluiting
Verwerk afsluitsignalen correct:
func main() {
server := &http.Server{
Addr: ":8080",
Handler: setupRouter(),
}
// Start server in goroutine
go func() {
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("Serverfout: %v", err)
}
}()
// Wacht op onderbrekingssein
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Server afsluiten...")
// Geef uitstaande verzoeken 30 seconden om te voltooien
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatalf("Server gedwongen af te sluiten: %v", err)
}
log.Println("Server is afgesloten")
}
Monitoring en observabiliteit
Structuurlogboek
Gebruik gestructureerde logboekregistratie voor betere zoekbaarheid:
import "go.uber.org/zap"
func setupLogger() (*zap.Logger, error) {
config := zap.NewProductionConfig()
config.OutputPaths = []string{"stdout"}
return config.Build()
}
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
logger := h.logger.With(
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("user_id", r.Context().Value("userID").(string)),
)
logger.Info("Verzoek verwerken")
// Handlerlogica
}
Metricsverzameling
Exposé van Prometheus-metrieken:
import "github.com/prometheus/client_golang/prometheus"
var (
requestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "Duur van HTTP-verzoeken",
},
[]string{"method", "path", "status"},
)
)
func init() {
prometheus.MustRegister(requestDuration)
}
func metricsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
recorder := &statusRecorder{ResponseWriter: w, status: 200}
next.ServeHTTP(recorder, r)
duration := time.Since(start).Seconds()
requestDuration.WithLabelValues(
r.Method,
r.URL.Path,
strconv.Itoa(recorder.status),
).Observe(duration)
})
}
Geavanceerde patronen
Werken met gestructureerde uitvoer
Wanneer je API’s bouwt die integreren met LLM’s, heb je mogelijk uitvoer beperken met gestructureerde uitvoer. Dit is vooral handig voor AI-geïntegreerde functies in je API.
Web scraping voor API-gegevensbronnen
Als je API gegevens moet verzamelen van andere websites, dan kan het begrijpen van alternatieven voor Beautiful Soup in Go je helpen om robuuste web scraping functionaliteit te implementeren.
Documentgeneratie
Veel API’s moeten documenten genereren. Voor PDF-generatie in Go zijn er verschillende bibliotheken en aanpakken die je kunt integreren in je API-eindpunten.
Semantische zoekopdrachten en herordenen
Voor API’s die te maken hebben met tekstzoekopdrachten en ophalen, kan het implementeren van herordenen met embeddingmodellen de relevantie van zoekresultaten aanzienlijk verbeteren.
Bouwen van MCP-servers
Als je API’s implementeert die het Model Context Protocol volgen, bekijk dan deze gids over het implementeren van MCP-servers in Go, die protocolspecificaties en praktische implementaties behandelt.
Veelvoorkomende valkuilen en oplossingen
Niet correct gebruik van contexten
Gebruik altijd contexten doorheen je aanroepketen. Dit biedt het juiste annuleren en timeoutbeheer.
negeren van goroutinelekken
Zorg ervoor dat alle goroutines kunnen afsluiten. Gebruik contexten met deadlines en zorg altijd voor een manier om voltooiing te signaleren.
slechte foutafhandeling
Geef geen ongecontroleerde databasefouten aan clients terug. Verpak fouten met context en geef gestructureerde berichten terug in API-antwoorden.
ontbrekende invoervalidatie
Valideer alle invoer op de grens. Vertrouw nooit op clientgegevens, zelfs niet van geverifieerde gebruikers.
onvoldoende testen
Test niet alleen de gelukkige route. Deek foutgevallen, randvoorwaarden en concurrentie scenario’s.
Samenvatting van beste praktijken
-
Begin eenvoudig: Start met de standaardbibliotheek. Voeg frameworks toe wanneer de complexiteit het vereist.
-
Laag je toepassing: Splits HTTP-handlers, bedrijfslogica en data toegang voor onderhoudbaarheid.
-
Valideer alles: Controleer invoer op grenzen. Gebruik sterke typing en validatiebibliotheken.
-
Behandel fouten consistent: Geef gestructureerde foutreacties. Log interne fouten maar geef ze niet bloot.
-
Gebruik middleware: Implementeer kruisende zorgen (authenticatie, logboekregistratie, metrieken) als middleware.
-
Test uitgebreid: Schrijf eenheidstests voor logica, integratiestests voor data toegang en eind- tot-eindtests voor workflows.
-
Documenteer je API: Gebruik OpenAPI/Swagger voor interactieve documentatie.
-
Monitor productie: Implementeer gestructureerde logboekregistratie, metriekverzameling en gezondheidstests.
-
Optimaliseer voorzichtig: Profielen voor optimalisatie. Gebruik caching, verbindingspooling en compressie waar nuttig.
-
Ontwerp voor vreedzame afsluiting: Verwerk afsluitsignalen en leeg verbindingscorrect.
Checklist voor het beginnen
Voor referentie bij het werken aan Go-projecten, kan het hebben van een comprehensieve Go cheat sheet de ontwikkeling versnellen en dienen als snelle referentie voor syntaxis en veelvoorkomende patronen.
Klaar om je eerste Go API te bouwen? Begin met deze stappen:
- ✅ Stel je Go-omgeving en projectstructuur in
- ✅ Kies tussen de standaardbibliotheek of een framework
- ✅ Implementeer basis CRUD-eindpunten
- ✅ Voeg aanvraagvalidatie en foutafhandeling toe
- ✅ Implementeer authenticatiemiddleware
- ✅ Voeg databaseintegratie met verbindingspooling toe
- ✅ Schrijf eenheidstests en integratiestests
- ✅ Voeg API-documentatie toe
- ✅ Implementeer logboekregistratie en metrieken
- ✅ Containerise met Docker
- ✅ Stel een CI/CD-pijplijn in
- ✅ Implementeer in productie met monitoring
Conclusie
Go biedt een uitstekende basis voor het bouwen van REST-Api’s, met een combinatie van prestaties, eenvoud en robuuste tooling. Of je nu microservices bouwt, interne tools of openbare Api’s, het ecosysteem van Go heeft rijpe oplossingen voor elk vereiste.
Het sleutel tot succes is het beginnen met solide architecturale patronen, het implementeren van correcte foutafhandeling en validatie vanaf het begin en het bouwen van uitgebreide testdekking. Naarmate je Api groeit, zullen de prestatiekenmerken en de sterke ondersteuning voor gelijktijdigheid van Go je goed dienen.
Onthoud dat het ontwikkelen van Api’s iteratief is. Start met een minimale haalbare implementatie, verzamel feedback en verfijn je aanpak op basis van echte gebruiksmogelijkheden. De snelle compilatie en de eenvoudige refactoring van Go maken deze iteratielus soepel en productief.
Nuttige links
- Go Cheat Sheet
- Vergelijking van Go ORMs voor PostgreSQL: GORM vs Ent vs Bun vs sqlc
- Meerwaardigheidsmodellen voor databases met voorbeelden in Go
- Alternatieven voor Beautiful Soup in Go
- PDF genereren in GO - Bibliotheken en voorbeelden
- Beperken van LLMs met gestructureerde uitvoer: Ollama, Qwen3 & Python of Go
- Herordenen van tekstdocumenten met Ollama en Qwen3 Embedding model - in Go
- Model Context Protocol (MCP), en aantekeningen over het implementeren van een MCP-server in Go
Externe bronnen
Officiële documentatie
- Officiële Go-documentatie - De officiële Go-documentatie en tutorials
- Go net/http-pakket - Documentatie van het standaardbibliothek HTTP-pakket
- Effective Go - Beste praktijken voor het schrijven van duidelijke, idiomatische Go-code
Populaire frameworks en bibliotheken
- Gin Web Framework - Snel HTTP-webframework met uitgebreide functies
- Chi Router - Lichte, idiomatische router voor het bouwen van Go-HTTP-diensten
- Echo Framework - Hoogprestatie, uitbreidbaar, minimalistisch webframework
- Fiber Framework - Express-inspiratie webframework gebouwd op Fasthttp
- GORM - De fantastische ORM-bibliotheek voor Golang
- golang-jwt - JWT-implemantatie voor Go
Testen en ontwikkelings-tools
- Testify - Toolkit met veelvoorkomende beweringen en mocks
- httptest-pakket - Standaardbibliotheek utiliteiten voor HTTP-testen
- Swaggo - Automatisch genereren van RESTful API-documentatie
- Air - Live reload voor Go-apps tijdens de ontwikkeling
Beste praktijken en gidsen
- Go Project Layout - Standaard Go-projectlay-outs
- Uber Go Style Guide - Uitgebreide Go-stylegids van Uber
- Go Code Review Comments - Vaak gemaakte opmerkingen tijdens Go-code reviews
- REST API Design Best Practices - Algemene REST API-designprincipes
Beveiliging en authenticatie
- OWASP Go Secure Coding Practices - Beveiligingsrichtlijnen voor Go-toepassingen
- OAuth2 voor Go - OAuth 2.0-implemantatie
- bcrypt-pakket - Implementatie van wachtwoordhashing
Prestaties en monitoring
- pprof - Ingebouwde profieltool voor Go-programma’s
- Prometheus Client - Prometheus-instrumentatiebibliotheek voor Go
- Zap Logger - Snel, gestructureerd, niveau-gebaseerd loggen