[{"content":"","externalUrl":null,"permalink":"/blog/articles/","section":"Articles","summary":"","title":"Articles","type":"articles"},{"content":"","externalUrl":null,"permalink":"/blog/comparisons/","section":"Comparisons","summary":"","title":"Comparisons","type":"comparisons"},{"content":"","externalUrl":null,"permalink":"/blog/releases/","section":"Releases","summary":"","title":"Releases","type":"releases"},{"content":"","date":"30 March 2026","externalUrl":null,"permalink":"/blog/tags/comparison/","section":"Tags","summary":"","title":"Comparison","type":"tags"},{"content":"","date":"30 March 2026","externalUrl":null,"permalink":"/blog/tags/go/","section":"Tags","summary":"","title":"Go","type":"tags"},{"content":"","date":"30 March 2026","externalUrl":null,"permalink":"/blog/tags/golang/","section":"Tags","summary":"","title":"Golang","type":"tags"},{"content":"","date":"30 March 2026","externalUrl":null,"permalink":"/blog/tags/huma/","section":"Tags","summary":"","title":"Huma","type":"tags"},{"content":"","date":"30 March 2026","externalUrl":null,"permalink":"/blog/tags/observability/","section":"Tags","summary":"","title":"Observability","type":"tags"},{"content":"","date":"30 March 2026","externalUrl":null,"permalink":"/blog/tags/openapi/","section":"Tags","summary":"","title":"Openapi","type":"tags"},{"content":"","date":"30 March 2026","externalUrl":null,"permalink":"/blog/tags/rest-api/","section":"Tags","summary":"","title":"Rest-Api","type":"tags"},{"content":"This post compares two Go frameworks for HTTP APIs: Huma and Rivaas. Both can produce OpenAPI docs from your code. They solve similar problems in different ways.\nDisclosure: Rivaas is our project. We wrote this comparison to explain real trade-offs, not to claim that one framework always wins. If you already use Chi, Gin, or another router with Huma, your reasons may still be valid after you read this.\nWho this is for # You are choosing a base layer for a Go HTTP API. You care about accurate API docs, validation, and how much wiring you do yourself. You are fine reading a few code snippets.\nWhat each project is # Huma is a small framework built around OpenAPI 3.1 and JSON Schema. You pick a router (for example Chi or Go 1.22 http.ServeMux) and wrap it with a Huma adapter. You register operations with input and output structs. Huma maps requests to those structs, validates with schema rules on struct tags, and serves /openapi.json, /docs, and related URLs by default. The project targets incremental adoption: bring your own router, middleware, and logging or metrics, keep docs aligned with code, and use generated tooling around the same models (Huma introduction). See Your First API and Bring Your Own Router.\nRivaas is a Go toolkit with a batteries-included app (rivaas.dev/app) and a standalone router (rivaas.dev/router). The router uses a radix tree (a compact path prefix tree) and a Bloom filter for fast route lookups. The app adds OpenTelemetry tracing, metrics, and structured logging, plus OpenAPI generation, request binding, validation, health endpoints, graceful shutdown, and TLS options. You can use packages on their own without the full app. See Rivaas documentation.\nArchitecture: who owns the server? # Huma stays router-agnostic. The host router listens and picks the handler. The Huma adapter turns the router’s request into a huma.Context, then calls your operation handler. That design helps you add Huma to an existing service without replacing the router.\nRivaas app owns the HTTP server lifecycle when you call app.New and Start: timeouts, shutdown, optional health routes, and observability hooks are part of the same layer. OpenAPI and Swagger UI on Rivaas are wired through app. If you only need routing speed or net/http handlers, you use router without app (no bundled document server on that path).\nSide-by-side technical points # Topic Huma Rivaas Go version Follow Huma’s go.mod (example tutorials use current Huma v2) Go 1.25+ for current Rivaas modules HTTP base Depends on the adapter (stdlib net/http for Chi and similar) net/http Router You choose (Chi, Gin, Echo, Fiber, ServeMux, …) Rivaas router (or you compose at a lower level) OpenAPI 3.1 default; 3.0.3 also available for older tools (docs) 3.0.4 and 3.1.2 via rivaas.dev/openapi Where the spec comes from Input/output structs and huma.Register / huma.Get metadata app.WithDoc, openapi.WithRequest / WithResponse, and your Go types (see note below the table). Validation JSON Schema rules on struct tags (maxLength, minimum, …) app.Context.Bind uses binding + validation (validate tags and optional custom rules). OpenAPI schemas reuse those tags for rules the generator understands, so docs and typical runtime checks stay aligned. Handler signature func(ctx context.Context, input *Input) (*Output, error) func(c *app.Context) with c.Bind, c.JSON, … Observability You bring metrics, tracing, and logging; Huma stays thin Built-in OpenTelemetry-style hooks on app (tracing, metrics, slog) Production extras You compose (middleware, probes, TLS) Health endpoints, lifecycle hooks, graceful shutdown, TLS / mTLS options on app Signals \u0026amp; shutdown You call http.Server.Shutdown (often from humacli OnStop; see Graceful Shutdown) app.Start listens for SIGINT (Ctrl+C) and SIGTERM and runs graceful shutdown; optional SIGHUP runs OnReload hooks on Unix (lifecycle hooks) Testing humatest builds a test API and helper HTTP calls (Writing Tests) Built-in helpers in rivaas.dev/app: methods on App (Test, TestJSON) and package helpers (ExpectJSON, TestContextWithBody, TestContextWithForm). They run handlers without starting a TCP server; see App.Test. You can still use httptest and router-level tests. Note (Rivaas — field rules in the OpenAPI document): The same struct tags you use for binding and validation (json, path, query, validate, …) feed field constraints in the spec. You do not add a parallel set of tags only for OpenAPI validation. The OpenAPI generator maps common rules to JSON Schema; an unusual validate tag might still run at runtime in Bind but not show up in the spec until the generator supports it—check the generated JSON for edge cases. Optional doc, example, and enum on fields add descriptions, samples, or allowed values in the spec; they are not a second validator.\nOpenAPI and types # Both projects try to keep the spec and the Go types in sync. When you change a field or tag, the generated document should change too.\nHuma puts request and response shape in nested structs with a Body field for JSON bodies. Struct tags carry both JSON names and documentation hints (example, doc) and schema rules (maxLength, format, …). That fits JSON Schema as the single source of validation rules.\nRivaas attaches documentation per route with app.WithDoc(...) and helpers from rivaas.dev/openapi. Normal Go types become request and response schemas; route-level summaries and descriptions come from WithDoc and related options, not from duplicating validation. Field-level constraints and documentation tags follow the note under the comparison table. Swagger UI is configured through OpenAPI options (for example openapi.WithSwaggerUI). More detail: Auto-Generate OpenAPI and Swagger UI in Go with Rivaas.\nBinding, validation, and errors # Huma: Path, query, header, and body fields are declared on the input struct. Invalid input typically returns 422 with a problem payload shaped by Huma’s schema validation (see the Writing Tests example with rating: 10).\nRivaas: Handlers call c.Bind(\u0026amp;dst) to read the body, path, query, and other sources into one struct. Bind runs validation when your types use validation tags or registered rules. Error responses often follow RFC 9457 (HTTP problem details). Use Fail, FailStatus, and helpers on app.Context together with rivaas.dev/errors when you want that shape. Teams that prefer manual checks can bind first and then run their own Validate() methods, as in the blog API example in the Rivaas repo.\nObservability and production operations # This is the biggest practical gap for many teams.\nWith Huma, you usually plug in OpenTelemetry or Prometheus yourself. Huma does not try to be a full application server; that keeps the core small and fits “we already have opinions on metrics.”\nWith Rivaas app, you can turn on tracing, metrics, and logging through app.WithObservability. Handlers get span and metric helpers on app.Context. For Kubernetes-style deployments, built-in liveness and readiness patterns and graceful shutdown reduce glue code. Background: Built-in Observability in Go with Rivaas.\nSignals and graceful shutdown # Huma does not stop the process for you. For a clean exit you call http.Server.Shutdown (often with a timeout context) when the service should stop. The Graceful Shutdown guide uses humacli: OnStop runs shutdown while ListenAndServe runs in OnStart. You can do the same with signal.NotifyContext in main if you prefer not to use that CLI. In all cases, connecting SIGINT / SIGTERM to Shutdown is your code.\nRivaas app builds signal handling into Start. SIGINT (Ctrl+C) and SIGTERM start graceful shutdown without signal.NotifyContext in your main for the usual case (app server guide). On Unix, if you register app.OnReload callbacks, SIGHUP runs those hooks—useful to reload config without exiting. If you register no reload hooks, SIGHUP is ignored so the process is not killed by a stray hangup. On Windows, SIGHUP does not exist; you can call Reload() from code instead. Details: Lifecycle hooks.\nPerformance notes # Rivaas publishes router benchmarks and explains how they are measured (Router performance). Huma’s cost is harder to separate from the host router you choose.\nIn most real APIs, database and network I/O matter more than routing time. Use benchmarks to check overhead, not to pick a winner from a single number.\nSmall example: same two endpoints # The snippets below are illustrative. They are shortened so you can see the shape of each style. You still need the correct import blocks (for example context, log, net/http, Chi, and Huma packages on the Huma side).\nHuma (Chi adapter) # Pattern from Your First API: create chi.NewMux(), humachi.New(router, huma.DefaultConfig(...)), then register operations. For 201 Created on POST, the tutorials use huma.Operation with DefaultStatus (Writing Tests).\nrouter := chi.NewMux() api := humachi.New(router, huma.DefaultConfig(\u0026#34;Users API\u0026#34;, \u0026#34;1.0.0\u0026#34;)) type UserOut struct { Body struct { ID int `json:\u0026#34;id\u0026#34; example:\u0026#34;1\u0026#34;` Email string `json:\u0026#34;email\u0026#34; example:\u0026#34;user@example.com\u0026#34;` } } huma.Get(api, \u0026#34;/users/{id}\u0026#34;, func(ctx context.Context, in *struct { ID int `path:\u0026#34;id\u0026#34; minimum:\u0026#34;1\u0026#34; doc:\u0026#34;User id\u0026#34;` }) (*UserOut, error) { out := \u0026amp;UserOut{} out.Body.ID = in.ID out.Body.Email = \u0026#34;user@example.com\u0026#34; return out, nil }) type CreateUserIn struct { Body struct { Email string `json:\u0026#34;email\u0026#34; format:\u0026#34;email\u0026#34;` } } huma.Register(api, huma.Operation{ Method: http.MethodPost, Path: \u0026#34;/users\u0026#34;, Summary: \u0026#34;Create user\u0026#34;, DefaultStatus: http.StatusCreated, }, func(ctx context.Context, in *CreateUserIn) (*UserOut, error) { out := \u0026amp;UserOut{} out.Body.ID = 42 out.Body.Email = in.Body.Email return out, nil }) log.Fatal(http.ListenAndServe(\u0026#34;127.0.0.1:8888\u0026#34;, router)) Rivaas (app) # Pattern from Rivaas README and the 02-blog example: app.New, app.WithOpenAPI, route registration with WithDoc.\na, err := app.New( app.WithOpenAPI( openapi.WithTitle(\u0026#34;users-api\u0026#34;, \u0026#34;1.0.0\u0026#34;), openapi.WithServer(\u0026#34;http://localhost:8080\u0026#34;, \u0026#34;local\u0026#34;), openapi.WithSwaggerUI(\u0026#34;/docs\u0026#34;), ), ) if err != nil { log.Fatal(err) } type getUserParams struct { ID int `path:\u0026#34;id\u0026#34; validate:\u0026#34;gt=0\u0026#34;` } a.GET(\u0026#34;/users/:id\u0026#34;, func(c *app.Context) { var p getUserParams if err := c.Bind(\u0026amp;p); err != nil { c.FailStatus(http.StatusBadRequest, err) return } _ = c.JSON(http.StatusOK, map[string]any{\u0026#34;id\u0026#34;: p.ID, \u0026#34;email\u0026#34;: \u0026#34;user@example.com\u0026#34;}) }, app.WithDoc( openapi.WithSummary(\u0026#34;Get user\u0026#34;), openapi.WithRequest(getUserParams{}), openapi.WithResponse(http.StatusOK, map[string]any{\u0026#34;id\u0026#34;: 0, \u0026#34;email\u0026#34;: \u0026#34;\u0026#34;}), )) type createUserBody struct { Email string `json:\u0026#34;email\u0026#34; validate:\u0026#34;required,email\u0026#34;` } a.POST(\u0026#34;/users\u0026#34;, func(c *app.Context) { var body createUserBody if err := c.Bind(\u0026amp;body); err != nil { c.FailStatus(http.StatusBadRequest, err) return } _ = c.JSON(http.StatusCreated, map[string]any{\u0026#34;id\u0026#34;: 42, \u0026#34;email\u0026#34;: body.Email}) }, app.WithDoc( openapi.WithSummary(\u0026#34;Create user\u0026#34;), openapi.WithRequest(createUserBody{}), openapi.WithResponse(http.StatusCreated, map[string]any{\u0026#34;id\u0026#34;: 0, \u0026#34;email\u0026#34;: \u0026#34;\u0026#34;}), )) if err := a.Start(context.Background()); err != nil { log.Fatal(err) } Imports for the Rivaas snippet are left out for space; you need context, log, net/http, rivaas.dev/app, and rivaas.dev/openapi.\nDefault HTTP port for app is 8080 unless you set app.WithPort.\nChoose Huma when… # You want to keep your current router and add OpenAPI, validation, and docs in one step. Your team likes handler functions that return (*Output, error) and a context.Context per call. You want validation rules to live mainly in JSON Schema-style struct tags. You prefer to assemble tracing and metrics yourself. Choose Rivaas when… # You want one app type that includes observability, health checks, shutdown, and optional TLS with fewer integrations. You want a fast Rivaas router and net/http middleware patterns documented in one place. You prefer RFC 9457 problem details wired through app.Context, with binding and validation as separate packages you can reuse outside app. You are starting a new service and do not need to keep an existing router API unchanged. Further reading # Huma: huma.rocks, Bring Your Own Router, Test utilities Rivaas: Documentation, Router performance On this blog: Auto-Generate OpenAPI and Swagger UI in Go with Rivaas, Built-in Observability in Go with Rivaas Broader context: Go API Frameworks Compared ","date":"30 March 2026","externalUrl":null,"permalink":"/blog/comparisons/rivaas-vs-huma/","section":"Comparisons","summary":"This post compares two Go frameworks for HTTP APIs: Huma and Rivaas. Both can produce OpenAPI docs from your code. They solve similar problems in different ways.\nDisclosure: Rivaas is our project. We wrote this comparison to explain real trade-offs, not to claim that one framework always wins. If you already use Chi, Gin, or another router with Huma, your reasons may still be valid after you read this.\nWho this is for # You are choosing a base layer for a Go HTTP API. You care about accurate API docs, validation, and how much wiring you do yourself. You are fine reading a few code snippets.\n","title":"Rivaas vs Huma: Go API Frameworks Compared","type":"comparisons"},{"content":"","date":"30 March 2026","externalUrl":null,"permalink":"/blog/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"Keeping an OpenAPI file up to date by hand is slow and easy to get wrong. Your code changes, but the spec does not, and clients stop trusting the docs. Rivaas helps by building the OpenAPI document when your app runs. You describe each route next to the handler, and your Go types become JSON Schema in the spec. This tutorial shows a small working API and where to open Swagger UI.\nOpenAPI is the standard format for describing HTTP APIs. Swagger UI is the page that lets you try requests against that description.\nHow Rivaas fits in # You turn on OpenAPI on the app with app.WithOpenAPI(...). For each route, you pass app.WithDoc(...) and options from rivaas.dev/openapi, such as openapi.WithSummary, openapi.WithRequest, and openapi.WithResponse.\nBy default the spec follows OpenAPI 3.0.x, which most tools understand well. If you need OpenAPI 3.1.x (closer to JSON Schema 2020-12), add openapi.WithVersion(openapi.V31x) inside app.WithOpenAPI.\nTools like swaggo/swag generate a spec from comments and need a build step. Here your types and WithDoc options stay close to the routes, and the spec is generated at runtime—no swag init for the spec itself.\nExample types # These structs are normal Go models. They are also what Rivaas uses to fill in request and response schemas in the spec when you reference them in WithDoc:\ntype CreateOrderRequest struct { CustomerID string `json:\u0026#34;customer_id\u0026#34; validate:\u0026#34;required\u0026#34;` Items []OrderItem `json:\u0026#34;items\u0026#34; validate:\u0026#34;required,min=1\u0026#34;` Notes string `json:\u0026#34;notes,omitempty\u0026#34;` } type OrderItem struct { ProductID string `json:\u0026#34;product_id\u0026#34; validate:\u0026#34;required\u0026#34;` Quantity int `json:\u0026#34;quantity\u0026#34; validate:\u0026#34;required,min=1\u0026#34;` } type CreateOrderResponse struct { OrderID string `json:\u0026#34;order_id\u0026#34;` Status string `json:\u0026#34;status\u0026#34;` CreatedAt time.Time `json:\u0026#34;created_at\u0026#34;` } Rivaas maps json tags to property names. It uses validation tags like validate:\u0026quot;required\u0026quot; to mark required fields where supported. Fields with omitempty are treated as optional in the schema. For edge cases and full rules, see the schema generation guide.\nStep 1: Create the project # mkdir orders-api \u0026amp;\u0026amp; cd orders-api go mod init example.com/orders go get rivaas.dev/app go get rivaas.dev/openapi Step 2: Add a full main.go # The app below enables OpenAPI and Swagger UI at /docs. It registers POST /orders with a documented request and response. MustBind reads and validates the JSON body; if something is wrong, Rivaas sends an error response and the handler returns early.\npackage main import ( \u0026#34;context\u0026#34; \u0026#34;log\u0026#34; \u0026#34;net/http\u0026#34; \u0026#34;time\u0026#34; \u0026#34;rivaas.dev/app\u0026#34; \u0026#34;rivaas.dev/openapi\u0026#34; ) type CreateOrderRequest struct { CustomerID string `json:\u0026#34;customer_id\u0026#34; validate:\u0026#34;required\u0026#34;` Items []OrderItem `json:\u0026#34;items\u0026#34; validate:\u0026#34;required,min=1\u0026#34;` Notes string `json:\u0026#34;notes,omitempty\u0026#34;` } type OrderItem struct { ProductID string `json:\u0026#34;product_id\u0026#34; validate:\u0026#34;required\u0026#34;` Quantity int `json:\u0026#34;quantity\u0026#34; validate:\u0026#34;required,min=1\u0026#34;` } type CreateOrderResponse struct { OrderID string `json:\u0026#34;order_id\u0026#34;` Status string `json:\u0026#34;status\u0026#34;` CreatedAt time.Time `json:\u0026#34;created_at\u0026#34;` } func main() { a, err := app.New( app.WithServiceName(\u0026#34;orders-api\u0026#34;), app.WithServiceVersion(\u0026#34;1.0.0\u0026#34;), app.WithOpenAPI( openapi.WithDescription(\u0026#34;Small example API with generated OpenAPI and Swagger UI.\u0026#34;), openapi.WithServer(\u0026#34;http://localhost:8080\u0026#34;, \u0026#34;Local\u0026#34;), openapi.WithSwaggerUI(\u0026#34;/docs\u0026#34;), ), ) if err != nil { log.Fatal(err) } a.POST(\u0026#34;/orders\u0026#34;, createOrder, app.WithDoc( openapi.WithSummary(\u0026#34;Create order\u0026#34;), openapi.WithRequest(CreateOrderRequest{}), openapi.WithResponse(http.StatusCreated, CreateOrderResponse{}), openapi.WithTags(\u0026#34;orders\u0026#34;), ), ) if err := a.Start(context.Background()); err != nil { log.Fatal(err) } } func createOrder(c *app.Context) { var req CreateOrderRequest if !c.MustBind(\u0026amp;req) { return } resp := CreateOrderResponse{ OrderID: \u0026#34;ord_001\u0026#34;, Status: \u0026#34;pending\u0026#34;, CreatedAt: time.Now().UTC(), } _ = c.JSON(http.StatusCreated, resp) } Step 3: Run the server and open Swagger UI # go run . GET /openapi.json — JSON document for your API. You can change the path with openapi.WithSpecPath if needed. GET /docs — Swagger UI (because of openapi.WithSwaggerUI(\u0026quot;/docs\u0026quot;)). Open http://localhost:8080/docs in a browser to explore and try the operation.\nStep 4: Optional API metadata and OpenAPI 3.1 # app.WithServiceName and app.WithServiceVersion feed into the spec’s title and version. You can also set them directly:\napp.WithOpenAPI( openapi.WithTitle(\u0026#34;Order Service API\u0026#34;, \u0026#34;1.0.0\u0026#34;), openapi.WithDescription(\u0026#34;Manage customer orders.\u0026#34;), openapi.WithVersion(openapi.V31x), // use 3.1.x; omit for default 3.0.x openapi.WithSwaggerUI(\u0026#34;/docs\u0026#34;), ) For auth in the spec, common helpers include openapi.WithBearerAuth and openapi.WithAPIKeyAuth. See OpenAPI configuration for the full list.\nCompare approaches # Approach Main source of truth Extra build step for the spec Stays aligned with handlers Hand-written YAML The spec file No Only if you edit the file every time swaggo Comments + code Yes (swag init) Mostly, if you maintain comments Rivaas Types + WithDoc No Yes, for routes you document More detail on operations and schemas # Per-route options (summaries, examples, security, multiple responses) are listed in the operation options reference and the operations guide. Validation tags such as validate:\u0026quot;min=1,max=100\u0026quot; can appear as JSON Schema limits where the generator supports them. Optional spec self-check (meta-validation) is off by default for speed; see validation if you want to turn it on in development or CI.\nNext steps # OpenAPI guides — install, configure, security, diagnostics App package: OpenAPI — how WithOpenAPI and WithDoc work together OpenAPI package reference Swagger UI options Run your service, open /docs, and use the live spec as the single place your team and clients read for this API.\n","date":"29 March 2026","externalUrl":null,"permalink":"/blog/articles/auto-openapi-swagger-go-rivaas/","section":"Articles","summary":"Keeping an OpenAPI file up to date by hand is slow and easy to get wrong. Your code changes, but the spec does not, and clients stop trusting the docs. Rivaas helps by building the OpenAPI document when your app runs. You describe each route next to the handler, and your Go types become JSON Schema in the spec. This tutorial shows a small working API and where to open Swagger UI.\n","title":"Auto-Generate OpenAPI and Swagger UI in Go with Rivaas","type":"articles"},{"content":"","date":"29 March 2026","externalUrl":null,"permalink":"/blog/tags/rivaas/","section":"Tags","summary":"","title":"Rivaas","type":"tags"},{"content":"","date":"29 March 2026","externalUrl":null,"permalink":"/blog/tags/swagger/","section":"Tags","summary":"","title":"Swagger","type":"tags"},{"content":"","date":"29 March 2026","externalUrl":null,"permalink":"/blog/tags/tutorial/","section":"Tags","summary":"","title":"Tutorial","type":"tags"},{"content":"Most Go web frameworks make you choose between simplicity and production features. With Rivaas, you get both. In this tutorial, you\u0026rsquo;ll build a REST API with automatic OpenAPI documentation, health probes, and interactive Swagger UI — all in under 5 minutes.\nPrerequisites # Go 1.25 or later A terminal and your favorite editor Step 1: Create Your Project # mkdir rivaas-quickstart \u0026amp;\u0026amp; cd rivaas-quickstart go mod init example.com/quickstart go get rivaas.dev/app go get rivaas.dev/openapi Step 2: Write Your First Handler # Create main.go:\npackage main import ( \u0026#34;context\u0026#34; \u0026#34;log\u0026#34; \u0026#34;net/http\u0026#34; \u0026#34;rivaas.dev/app\u0026#34; \u0026#34;rivaas.dev/openapi\u0026#34; ) func main() { a, err := app.New( app.WithHealthEndpoints(), app.WithOpenAPI( openapi.WithTitle(\u0026#34;Quickstart API\u0026#34;, \u0026#34;1.0.0\u0026#34;), ), ) if err != nil { log.Fatal(err) } a.GET(\u0026#34;/hello\u0026#34;, func(c *app.Context) { c.JSON(http.StatusOK, map[string]string{ \u0026#34;message\u0026#34;: \u0026#34;Hello from Rivaas!\u0026#34;, }) }) if err := a.Start(context.Background()); err != nil { log.Fatal(err) } } Step 3: Run It # go run main.go Your API is now running on http://localhost:8080 with several endpoints ready out of the box.\nStep 4: Explore the Built-in Endpoints # Rivaas gives you production-ready endpoints without any extra configuration:\nEndpoint What It Does /hello Your handler /livez Liveness probe (returns 200) /readyz Readiness probe (returns 204) /openapi.json Auto-generated OpenAPI 3.1 specification /docs Interactive Swagger UI Try them:\ncurl http://localhost:8080/hello curl http://localhost:8080/livez curl http://localhost:8080/openapi.json Open http://localhost:8080/docs in your browser to see the interactive API documentation — generated automatically from your registered routes and Go types.\nStep 5: Add Request Binding # Let\u0026rsquo;s make the API more interesting with typed request handling. Add this inside main(), after the GET handler:\ntype CreateUserRequest struct { Name string `json:\u0026#34;name\u0026#34; validate:\u0026#34;required\u0026#34;` Email string `json:\u0026#34;email\u0026#34; validate:\u0026#34;required,email\u0026#34;` } a.POST(\u0026#34;/users\u0026#34;, func(c *app.Context) { var req CreateUserRequest if err := c.Bind(\u0026amp;req); err != nil { return } c.JSON(http.StatusCreated, map[string]string{ \u0026#34;message\u0026#34;: \u0026#34;User created\u0026#34;, \u0026#34;name\u0026#34;: req.Name, }) }) Rivaas automatically validates the request body, returns structured error messages, and updates the OpenAPI spec to include the new endpoint.\nWhat You Get Out of the Box # With the options used above, your Rivaas application includes:\nLiveness and readiness probes at /livez and /readyz OpenAPI 3.1 spec generated from your registered routes and Go types Interactive Swagger UI at /docs Graceful shutdown — Start handles SIGINT/SIGTERM built-in, no signal setup needed Panic recovery middleware Need observability? Add WithObservability() to enable structured logging, OpenTelemetry tracing, and Prometheus metrics — each configurable independently.\nNext Steps # First application — a deeper walkthrough of the full app setup App guide — lifecycle, middleware, and server configuration Binding guide — JSON, query params, path params, and validation OpenAPI guide — customize your auto-generated API docs ","date":"7 March 2026","externalUrl":null,"permalink":"/blog/articles/getting-started-rivaas-5-minutes/","section":"Articles","summary":"Most Go web frameworks make you choose between simplicity and production features. With Rivaas, you get both. In this tutorial, you’ll build a REST API with automatic OpenAPI documentation, health probes, and interactive Swagger UI — all in under 5 minutes.\nPrerequisites # Go 1.25 or later A terminal and your favorite editor Step 1: Create Your Project # mkdir rivaas-quickstart \u0026\u0026 cd rivaas-quickstart go mod init example.com/quickstart go get rivaas.dev/app go get rivaas.dev/openapi Step 2: Write Your First Handler # Create main.go:\n","title":"Getting Started with Rivaas in 5 Minutes","type":"articles"},{"content":"","date":"7 March 2026","externalUrl":null,"permalink":"/blog/tags/getting-started/","section":"Tags","summary":"","title":"Getting-Started","type":"tags"},{"content":"","externalUrl":null,"permalink":"/blog/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/blog/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"Articles, comparisons, and release notes for the Rivaas Go framework.\n","externalUrl":null,"permalink":"/blog/","section":"Rivaas Blog","summary":"Articles, comparisons, and release notes for the Rivaas Go framework.\n","title":"Rivaas Blog","type":"page"}]