docs(api): add AX usage examples
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
e2935ce79e
commit
b341b4b860
5 changed files with 80 additions and 0 deletions
13
client.go
13
client.go
|
|
@ -20,6 +20,11 @@ import (
|
|||
// OpenAPIClient is a small runtime client that can call operations by their
|
||||
// OpenAPI operationId. It loads the spec once, resolves the HTTP method and
|
||||
// path for each operation, and performs JSON request/response handling.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// client := api.NewOpenAPIClient(api.WithSpec("./openapi.yaml"), api.WithBaseURL("https://api.example.com"))
|
||||
// data, err := client.Call("get_health", nil)
|
||||
type OpenAPIClient struct {
|
||||
specPath string
|
||||
baseURL string
|
||||
|
|
@ -78,6 +83,10 @@ func WithHTTPClient(client *http.Client) OpenAPIClientOption {
|
|||
}
|
||||
|
||||
// NewOpenAPIClient constructs a runtime client for calling OpenAPI operations.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// client := api.NewOpenAPIClient(api.WithSpec("./openapi.yaml"))
|
||||
func NewOpenAPIClient(opts ...OpenAPIClientOption) *OpenAPIClient {
|
||||
c := &OpenAPIClient{
|
||||
httpClient: http.DefaultClient,
|
||||
|
|
@ -97,6 +106,10 @@ func NewOpenAPIClient(opts ...OpenAPIClientOption) *OpenAPIClient {
|
|||
// include "path", "query", "header", "cookie", and "body" keys to explicitly
|
||||
// control where the values are sent. When no explicit body is provided,
|
||||
// requests with a declared requestBody send the remaining parameters as JSON.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// data, err := client.Call("create_item", map[string]any{"name": "alpha"})
|
||||
func (c *OpenAPIClient) Call(operationID string, params any) (any, error) {
|
||||
if err := c.load(); err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
12
codegen.go
12
codegen.go
|
|
@ -32,6 +32,10 @@ var supportedLanguages = map[string]string{
|
|||
}
|
||||
|
||||
// SDKGenerator wraps openapi-generator-cli for SDK generation.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// gen := &api.SDKGenerator{SpecPath: "./openapi.yaml", OutputDir: "./sdk", PackageName: "service"}
|
||||
type SDKGenerator struct {
|
||||
// SpecPath is the path to the OpenAPI spec file (JSON or YAML).
|
||||
SpecPath string
|
||||
|
|
@ -45,6 +49,10 @@ type SDKGenerator struct {
|
|||
|
||||
// Generate creates an SDK for the given language using openapi-generator-cli.
|
||||
// The language must be one of the supported languages returned by SupportedLanguages().
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// err := gen.Generate(context.Background(), "go")
|
||||
func (g *SDKGenerator) Generate(ctx context.Context, language string) error {
|
||||
generator, ok := supportedLanguages[language]
|
||||
if !ok {
|
||||
|
|
@ -94,6 +102,10 @@ func (g *SDKGenerator) Available() bool {
|
|||
|
||||
// SupportedLanguages returns the list of supported SDK target languages
|
||||
// in sorted order for deterministic output.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// langs := api.SupportedLanguages()
|
||||
func SupportedLanguages() []string {
|
||||
return slices.Sorted(maps.Keys(supportedLanguages))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ import (
|
|||
)
|
||||
|
||||
// SpecBuilder constructs an OpenAPI 3.1 specification from registered RouteGroups.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// builder := &api.SpecBuilder{Title: "Service", Version: "1.0.0"}
|
||||
// spec, err := builder.Build(engine.Groups())
|
||||
type SpecBuilder struct {
|
||||
Title string
|
||||
Description string
|
||||
|
|
@ -21,6 +26,10 @@ type SpecBuilder struct {
|
|||
// Build generates the complete OpenAPI 3.1 JSON spec.
|
||||
// Groups implementing DescribableGroup contribute endpoint documentation.
|
||||
// Other groups are listed as tags only.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// data, err := (&api.SpecBuilder{Title: "Service", Version: "1.0.0"}).Build(engine.Groups())
|
||||
func (sb *SpecBuilder) Build(groups []RouteGroup) ([]byte, error) {
|
||||
spec := map[string]any{
|
||||
"openapi": "3.1.0",
|
||||
|
|
|
|||
25
response.go
25
response.go
|
|
@ -5,6 +5,11 @@ package api
|
|||
import "github.com/gin-gonic/gin"
|
||||
|
||||
// Response is the standard envelope for all API responses.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// resp := api.OK(map[string]any{"id": 42})
|
||||
// resp.Success // true
|
||||
type Response[T any] struct {
|
||||
Success bool `json:"success"`
|
||||
Data T `json:"data,omitempty"`
|
||||
|
|
@ -29,6 +34,10 @@ type Meta struct {
|
|||
}
|
||||
|
||||
// OK wraps data in a successful response envelope.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// c.JSON(http.StatusOK, api.OK(map[string]any{"name": "status"}))
|
||||
func OK[T any](data T) Response[T] {
|
||||
return Response[T]{
|
||||
Success: true,
|
||||
|
|
@ -37,6 +46,10 @@ func OK[T any](data T) Response[T] {
|
|||
}
|
||||
|
||||
// Fail creates an error response with the given code and message.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// c.JSON(http.StatusBadRequest, api.Fail("invalid_input", "Name is required"))
|
||||
func Fail(code, message string) Response[any] {
|
||||
return Response[any]{
|
||||
Success: false,
|
||||
|
|
@ -48,6 +61,10 @@ func Fail(code, message string) Response[any] {
|
|||
}
|
||||
|
||||
// FailWithDetails creates an error response with additional detail payload.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// c.JSON(http.StatusBadRequest, api.FailWithDetails("invalid_input", "Name is required", map[string]any{"field": "name"}))
|
||||
func FailWithDetails(code, message string, details any) Response[any] {
|
||||
return Response[any]{
|
||||
Success: false,
|
||||
|
|
@ -60,6 +77,10 @@ func FailWithDetails(code, message string, details any) Response[any] {
|
|||
}
|
||||
|
||||
// Paginated wraps data in a successful response with pagination metadata.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// c.JSON(http.StatusOK, api.Paginated(items, 2, 50, 200))
|
||||
func Paginated[T any](data T, page, perPage, total int) Response[T] {
|
||||
return Response[T]{
|
||||
Success: true,
|
||||
|
|
@ -75,6 +96,10 @@ func Paginated[T any](data T, page, perPage, total int) Response[T] {
|
|||
// AttachRequestMeta merges request metadata into an existing response envelope.
|
||||
// Existing pagination metadata is preserved; request_id and duration are added
|
||||
// when available from the Gin context.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// resp = api.AttachRequestMeta(c, resp)
|
||||
func AttachRequestMeta[T any](c *gin.Context, resp Response[T]) Response[T] {
|
||||
meta := GetRequestMeta(c)
|
||||
if meta == nil {
|
||||
|
|
|
|||
21
sse.go
21
sse.go
|
|
@ -15,6 +15,11 @@ import (
|
|||
// to subscribed clients. Clients connect via a GET endpoint and receive
|
||||
// a streaming text/event-stream response. Each client may optionally
|
||||
// subscribe to a specific channel via the ?channel= query parameter.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// broker := api.NewSSEBroker()
|
||||
// engine.GET("/events", broker.Handler())
|
||||
type SSEBroker struct {
|
||||
mu sync.RWMutex
|
||||
wg sync.WaitGroup
|
||||
|
|
@ -37,6 +42,10 @@ type sseEvent struct {
|
|||
}
|
||||
|
||||
// NewSSEBroker creates a ready-to-use SSE broker.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// broker := api.NewSSEBroker()
|
||||
func NewSSEBroker() *SSEBroker {
|
||||
return &SSEBroker{
|
||||
clients: make(map[*sseClient]struct{}),
|
||||
|
|
@ -46,6 +55,10 @@ func NewSSEBroker() *SSEBroker {
|
|||
// Publish sends an event to all clients subscribed to the given channel.
|
||||
// Clients subscribed to an empty channel (no ?channel= param) receive
|
||||
// events on every channel. The data value is JSON-encoded before sending.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// broker.Publish("system", "ready", map[string]any{"status": "ok"})
|
||||
func (b *SSEBroker) Publish(channel, event string, data any) {
|
||||
encoded, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
|
|
@ -81,6 +94,10 @@ func (b *SSEBroker) Publish(channel, event string, data any) {
|
|||
// Handler returns a Gin handler for the SSE endpoint. Clients connect with
|
||||
// a GET request and receive events as text/event-stream. An optional
|
||||
// ?channel=<name> query parameter subscribes the client to a specific channel.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// engine.GET("/events", broker.Handler())
|
||||
func (b *SSEBroker) Handler() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
channel := c.Query("channel")
|
||||
|
|
@ -154,6 +171,10 @@ func (b *SSEBroker) ClientCount() int {
|
|||
|
||||
// Drain signals all connected clients to disconnect and waits for their
|
||||
// handler goroutines to exit. Useful for graceful shutdown.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// broker.Drain()
|
||||
func (b *SSEBroker) Drain() {
|
||||
b.mu.Lock()
|
||||
for client := range b.clients {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue