Backend API Overview

The Nester backend is built with Go + Chi router, serving as the API gateway between the frontend and blockchain/external services.

Base Configuration

go
package main

import (
    "log/slog"
    "net/http"
    "os"

    "github.com/go-chi/chi/v5"
    "github.com/go-chi/chi/v5/middleware"
    "github.com/go-chi/cors"
)

func main() {
    logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

    r := chi.NewRouter()

    // Middleware
    r.Use(middleware.RequestID)
    r.Use(middleware.RealIP)
    r.Use(middleware.Logger)
    r.Use(middleware.Recoverer)
    r.Use(cors.Handler(cors.Options{
        AllowedOrigins:   []string{"https://nester.finance", "http://localhost:3001"},
        AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
        AllowedHeaders:   []string{"Accept", "Authorization", "Content-Type"},
        AllowCredentials: true,
    }))
    r.Use(middleware.Timeout(30 * time.Second))

    // Routes
    r.Route("/api/v1", func(r chi.Router) {
        r.Route("/vaults", vaultRoutes)
        r.Route("/positions", positionRoutes)
        r.Route("/yields", yieldRoutes)
        r.Route("/offramp", offrampRoutes)
        r.Route("/users", userRoutes)
    })

    // Health check
    r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte(`{"status":"ok"}`))
    })

    logger.Info("starting server", "port", 8080)
    http.ListenAndServe(":8080", r)
}

API Response Envelope

All API responses follow a consistent envelope:

go
type APIResponse struct {
    Success bool        `json:"success"`
    Data    interface{} `json:"data,omitempty"`
    Error   *APIError   `json:"error,omitempty"`
    Meta    *Meta       `json:"meta,omitempty"`
}

type APIError struct {
    Code    string `json:"code"`
    Message string `json:"message"`
}

// Example success response
{
    "success": true,
    "data": { "vault_id": "abc-123", "shares": 1000 }
}

// Example error response
{
    "success": false,
    "error": { "code": "INSUFFICIENT_BALANCE", "message": "Not enough USDC" }
}