# Rony [![Go Reference](https://pkg.go.dev/badge/github.com/clubpay/ronykit/rony.svg)](https://pkg.go.dev/github.com/clubpay/ronykit/rony) [![Go Report Card](https://goreportcard.com/badge/github.com/clubpay/ronykit/rony)](https://goreportcard.com/report/github.com/clubpay/ronykit/rony) Rony is the batteries-included API and edge server framework in RonyKIT. It provides a compact, type-safe API powered by Go generics and built on top of the `kit` core. If you need full control over gateways or clusters, use the lower-level [Kit package](../kit/README.MD). - [Installation](#installation) - [Quick Start](#quick-start) - [Core Concepts](#core-concepts) - [Minimal Example](#minimal-example) - [More Examples](#more-examples) ## Installation Install the project scaffold tool: ```shell go install github.com/clubpay/ronykit/ronyup@latest ``` ## Quick Start Create a new project with `ronyup`: ```shell ronyup setup -d ./my-project -m github.com/ehsannm/myproject -p MyProjectName ``` ## Core Concepts - **State**: a shared, reducer-style state per service. Implement `Name()` and `Reduce(action) error`. If you do not need state, use `rony.EmptyState()`. - **Handlers**: unary or streaming functions. Unary handlers receive `*rony.UnaryCtx` and a request DTO, then return a response DTO. - **Contracts**: route definitions that bind handlers to REST or RPC selectors. State interface signature: ```go package rony type ( Action comparable State[A Action] interface { Name() string Reduce(action A) error } ) ``` ## Minimal Example ```go package main import ( "context" "fmt" "os" "strings" "sync" "github.com/clubpay/ronykit/rony" "github.com/clubpay/ronykit/rony/errs" ) type Counter struct { sync.Mutex Count int } func (c *Counter) Name() string { return "Counter" } func (c *Counter) Reduce(action string) error { switch strings.ToLower(action) { case "up": c.Count++ case "down": if c.Count <= 0 { return fmt.Errorf("count cannot be negative") } c.Count-- default: return fmt.Errorf("unknown action: %s", action) } return nil } type CounterRequest struct { Action string `json:"action"` } type CounterResponse struct { Count int `json:"count"` } func count(ctx *rony.UnaryCtx[*Counter, string], req CounterRequest) (*CounterResponse, error) { res := &CounterResponse{} err := ctx.ReduceState(req.Action, func(s *Counter, err error) error { if err != nil { return errs.WrapCode(err, errs.InvalidArgument, "BAD_REQUEST") } res.Count = s.Count return nil }) if err != nil { return nil, err } return res, nil } func main() { srv := rony.NewServer( rony.Listen(":80"), rony.WithServerName("CounterServer"), ) rony.Setup( srv, "CounterService", rony.ToInitiateState[*Counter, string](&Counter{Count: 0}), rony.WithUnary( count, rony.GET("/count/{action}"), rony.GET("/count"), ), ) if err := srv.Run(context.Background(), os.Interrupt, os.Kill); err != nil { panic(err) } } ``` ## More Examples - [Getting Started Guide](../docs/getting-started.md) - [Cookbook](../docs/cookbook.md) — production patterns for auth, pagination, validation, and more - [ronyup Guide](../docs/ronyup-guide.md) — scaffolding CLI and MCP server - [Runnable examples](../example)