Go HTTP APIs
Go can own HTTP routing and responses while a Nubo script calls host functions and produces a result. You do not need to expose *http.Request or http.ResponseWriter to the reflection bridge.
This complete example has two files. Go embeds the script, exposes a request-specific function, and writes the script’s JSON result.
Nubo handler
Section titled “Nubo handler”import json from "@std/json"
let name = RequestName()
return json.stringify(dict[string, any] { message: "Hello, " + name, ok: true})Go server
Section titled “Go server”package main
import ( _ "embed" "fmt" "log" "net/http" "sync" "time"
"github.com/nubolang/nubo")
//go:embed api.nubovar apiSource string
var scriptMu sync.Mutex
func render(name string) (string, error) { scriptMu.Lock() defer scriptMu.Unlock()
app := nubo.New()
err := app.AddFunc("RequestName", nubo.GoFunc(func() string { return name })) if err != nil { return "", err }
result, err := app.ExecString(apiSource) if err != nil { return "", err }
if result == nil { return "", fmt.Errorf("API script returned no result") }
body, ok := result.Value().(string) if !ok { return "", fmt.Errorf("API script must return JSON text") }
return body, nil}
func hello(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { w.Header().Set("Allow", http.MethodGet) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return }
name := r.URL.Query().Get("name") if name == "" { name = "World" }
body, err := render(name) if err != nil { log.Printf("Nubo API failed: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) return }
w.Header().Set("Content-Type", "application/json; charset=utf-8") _, _ = w.Write([]byte(body))}
func main() { mux := http.NewServeMux() mux.HandleFunc("/hello", hello)
server := &http.Server{ Addr: ":8080", Handler: mux, ReadHeaderTimeout: 5 * time.Second, }
log.Fatal(server.ListenAndServe())}After adding Nubo to your Go module, run the host with go run .. GET /hello?name=Ada returns:
{"message":"Hello, Ada","ok":true}The example creates a fresh application context per call and serializes script execution. It does not assume arbitrary concurrent access to interpreter state or shared standard-library objects is safe. Request-specific data is passed through callbacks rather than interpolated into Nubo source.
Grow the API
Section titled “Grow the API”Expose supported Go functions for application services or register a hybrid package to give those services a typed Nubo API. Keep routing, authentication, body limits, and HTTP status decisions in the host unless you deliberately expose script operations for them.
A leading context.Context in a reflected function receives the interpreter’s context. It is not automatically the incoming r.Context(); the public API currently has no request-context setter. A callback can close over the request context when calling a host service that needs cancellation.
Or use Nubo’s built-in server
Section titled “Or use Nubo’s built-in server”With nubo serve, route scripts receive @server/request and @server/response automatically. Ordinary ExecString calls do not have those request-specific bindings.
The public github.com/nubolang/nubo/server package also implements http.Handler. If embedding that server, initialize configuration with config.Verify() (or load your chosen configuration), create it with server.New(directory), and attach the resulting handler to your Go HTTP server. See the server guide for its file routing and module APIs.