Documentation
¶
Index ¶
- Constants
- func BenchReleaseCtx(c *Ctx)
- func ErrBadRequest(code, message string) error
- func ErrConflict(code, message string) error
- func ErrForbidden(code, message string) error
- func ErrGatewayTimeout(message string) error
- func ErrInternal(code, message string) error
- func ErrInvalidBody(message string) error
- func ErrMethodNotAllowed(message string) error
- func ErrNotFound(code, message string) error
- func ErrNotImplemented(message string) error
- func ErrPayloadTooLarge(message string) error
- func ErrServiceUnavailable(message string) error
- func ErrTimeout(message string) error
- func ErrTooManyRequests(message string) error
- func ErrUnauthorized(code, message string) error
- func ErrUnprocessable(code, message string) error
- func Get[T any](ctx *Ctx, key string) (T, bool)
- func InitTestCtx(c *Ctx, w http.ResponseWriter, r *http.Request)
- func LoadConfig[T any]() (T, error)
- func MustGet[T any](ctx *Ctx, key string) T
- func SetStreamTestParam(s *StreamCtx, key, value string)
- func SetStreamTestStore(s *StreamCtx, key string, val any)
- func SetTestBody(c *Ctx, b []byte)
- func SetTestParam(c *Ctx, key, value string)
- type App
- func (a *App) Guard(guards ...Guard) *App
- func (a *App) Listen() error
- func (a *App) LivenessHandler() HandlerFunc
- func (a *App) OpenAPISpec() map[string]any
- func (a *App) ReadinessHandler() HandlerFunc
- func (a *App) Register(modules ...Module) *App
- func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (a *App) Shutdown(ctx context.Context) error
- func (a *App) Use(mw ...MiddlewareFunc) *App
- type BastError
- type BodySchema
- type Config
- type Controller
- type Ctx
- func (c *Ctx) Bind(v any) error
- func (c *Ctx) BindForm(v any) error
- func (c *Ctx) BindJSON(v any) error
- func (c *Ctx) Context() context.Context
- func (c *Ctx) Cookie(name string) (*http.Cookie, error)
- func (c *Ctx) Cookies() []*http.Cookie
- func (c *Ctx) Created(data any) Response
- func (c *Ctx) Error(err error) Response
- func (c *Ctx) File(field string) (*multipart.FileHeader, error)
- func (c *Ctx) Files(field string) ([]*multipart.FileHeader, error)
- func (c *Ctx) FormValue(key string) string
- func (c *Ctx) Get(key string) (any, bool)
- func (c *Ctx) Header(key string) string
- func (c *Ctx) IP() string
- func (c *Ctx) Method() string
- func (c *Ctx) MustGet(key string) any
- func (c *Ctx) NoContent() Response
- func (c *Ctx) OK(data any) Response
- func (c *Ctx) Paginated(data any, meta PaginationMeta) Response
- func (c *Ctx) Param(key string) string
- func (c *Ctx) Path() string
- func (c *Ctx) Query(key string) string
- func (c *Ctx) QueryDefault(key, fallback string) string
- func (c *Ctx) Raw(status int, contentType string, body []byte) Response
- func (c *Ctx) RawBody() ([]byte, error)
- func (c *Ctx) Redirect(url string, code int) Response
- func (c *Ctx) Set(key string, val any)
- func (c *Ctx) WithCookie(cookie *http.Cookie) Response
- func (c *Ctx) WithValue(key, val any) *Ctx
- type Doc
- type DocsConfig
- type ErrorHandler
- type Guard
- type GuardFunc
- type HandlerFunc
- type HealthCheck
- type HealthConfig
- type Hooks
- type Logger
- type MiddlewareFunc
- type Module
- type ModuleDoc
- type PaginationMeta
- type Param
- type Response
- func (r Response) Body() []byte
- func (r Response) ContentType() string
- func (r Response) Cookies() []*http.Cookie
- func (r Response) Err() error
- func (r Response) Headers() map[string]string
- func (r Response) IsError() bool
- func (r Response) Redirect() string
- func (r Response) Status() int
- func (r Response) WithCookie(cookie *http.Cookie) Response
- func (r Response) WithHeader(key, value string) Response
- func (r Response) WithStatus(code int) Response
- type Returns
- type Route
- func DELETE(pattern string, handler HandlerFunc, opts ...RouteOption) Route
- func GET(pattern string, handler HandlerFunc, opts ...RouteOption) Route
- func PATCH(pattern string, handler HandlerFunc, opts ...RouteOption) Route
- func POST(pattern string, handler HandlerFunc, opts ...RouteOption) Route
- func PUT(pattern string, handler HandlerFunc, opts ...RouteOption) Route
- func STREAM(pattern string, handler StreamHandlerFunc, opts ...RouteOption) Route
- type RouteOption
- type SecuredGuard
- type SecurityScheme
- type StreamCtx
- func (s *StreamCtx) Closed() <-chan struct{}
- func (s *StreamCtx) Flush() error
- func (s *StreamCtx) Get(key string) (any, bool)
- func (s *StreamCtx) MustGet(key string) any
- func (s *StreamCtx) Param(key string) string
- func (s *StreamCtx) Send(event, data string) error
- func (s *StreamCtx) Set(key string, val any)
- func (s *StreamCtx) SetHeader(key, value string)
- func (s *StreamCtx) Status(code int)
- func (s *StreamCtx) Write(p []byte) (int, error)
- type StreamHandlerFunc
- type ValidationError
- type Validator
Constants ¶
const ( CodeBadRequest = "BAD_REQUEST" CodeInvalidBody = "INVALID_BODY" CodeForbidden = "FORBIDDEN" CodeNotFound = "NOT_FOUND" CodeMethodNotAllowed = "METHOD_NOT_ALLOWED" CodeTimeout = "REQUEST_TIMEOUT" CodeConflict = "CONFLICT" CodePayloadTooLarge = "PAYLOAD_TOO_LARGE" CodeUnprocessable = "UNPROCESSABLE_ENTITY" CodeValidation = "VALIDATION_FAILED" CodeTooManyRequests = "TOO_MANY_REQUESTS" CodeInternal = "INTERNAL_ERROR" CodeNotImplemented = "NOT_IMPLEMENTED" CodeGatewayTimeout = "GATEWAY_TIMEOUT" )
Variables ¶
This section is empty.
Functions ¶
func BenchReleaseCtx ¶
func BenchReleaseCtx(c *Ctx)
func ErrBadRequest ¶
func ErrConflict ¶
func ErrForbidden ¶
func ErrGatewayTimeout ¶
func ErrInternal ¶
func ErrInvalidBody ¶
func ErrMethodNotAllowed ¶
func ErrNotFound ¶
func ErrNotImplemented ¶
func ErrPayloadTooLarge ¶
func ErrServiceUnavailable ¶
func ErrTimeout ¶
func ErrTooManyRequests ¶
func ErrUnauthorized ¶
func ErrUnprocessable ¶
func InitTestCtx ¶
func InitTestCtx(c *Ctx, w http.ResponseWriter, r *http.Request)
InitTestCtx wires a writer and request onto a test Ctx. For basttest only.
func LoadConfig ¶
LoadConfig loads and validates configuration from environment variables. T must be a struct. Reflection runs once at startup — never on the hot path.
Supported tags:
env:"VAR_NAME" — environment variable name default:"value" — used when env var is absent required:"true" — app refuses to start if absent and no default secret:"true" — value is masked in boot logs
Supported field types: string, int, int64, float64, bool, time.Duration, []string Nested structs: env tag on the struct field acts as a prefix (e.g. env:"DB" → DB_URL).
func SetStreamTestParam ¶ added in v0.2.0
SetStreamTestParam sets a route path parameter on a test StreamCtx. For basttest only.
func SetStreamTestStore ¶ added in v0.2.0
SetStreamTestStore sets a value in the store of a test StreamCtx. For basttest only.
func SetTestBody ¶
SetTestBody pre-loads the body buffer on a test Ctx so readBody() is skipped. For basttest only.
func SetTestParam ¶
SetTestParam sets a route param on a test Ctx. For basttest only.
Types ¶
type App ¶
type App struct {
// contains filtered or unexported fields
}
App is the Bast application. Satisfies http.Handler.
func (*App) Listen ¶
Listen starts the HTTP server on the configured port. Uses net.Listen so OnReady fires after the port is bound, before first connections.
func (*App) LivenessHandler ¶
func (a *App) LivenessHandler() HandlerFunc
LivenessHandler returns a HandlerFunc for the liveness probe. Always returns 200 as long as the process is alive — never checks dependencies.
func (*App) OpenAPISpec ¶
OpenAPISpec returns the built OpenAPI spec, or nil if docs are not configured. The spec is built once when this method is first called — safe to call multiple times.
func (*App) ReadinessHandler ¶
func (a *App) ReadinessHandler() HandlerFunc
ReadinessHandler returns a HandlerFunc for the readiness probe. Returns 200 if all checks pass, 503 if any check fails.
func (*App) ServeHTTP ¶
func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP satisfies http.Handler.
func (*App) Shutdown ¶
Shutdown gracefully shuts down the server. If ctx carries no deadline, Config.ShutdownTimeout is applied.
func (*App) Use ¶
func (a *App) Use(mw ...MiddlewareFunc) *App
Use registers global middleware. Runs for every request.
type BastError ¶
type BastError struct {
Status int `json:"-"`
Code string `json:"code"`
Message string `json:"message"`
}
BastError is the typed error Bast understands. Use the constructors.
type BodySchema ¶
type BodySchema struct {
Example any
}
BodySchema holds a reflected type for OpenAPI schema generation. Populated via Body[T]() — reflection runs once at startup, never on hot path.
func Body ¶
func Body[T any]() *BodySchema
Body captures a type for OpenAPI schema generation. Reflection runs once at startup — zero cost at request time.
type Config ¶
type Config struct {
Port int
// ReadTimeout / WriteTimeout have no default: a default WriteTimeout would
// kill long-lived SSE streams and a default ReadTimeout would kill slow
// uploads. Set them if your app serves neither. Use HandlerTimeout for
// per-request protection instead.
ReadTimeout time.Duration
WriteTimeout time.Duration
// IdleTimeout defaults to 120s; ReadHeaderTimeout defaults to 10s
// (slowloris protection). Set to -1 to disable.
IdleTimeout time.Duration
ReadHeaderTimeout time.Duration
MaxBodySize int64
// HandlerTimeout is the global per-request deadline applied to every
// non-stream route without an explicit route-level Timeout. Handlers see it
// via ctx.Context() cancellation. 0 means no global deadline.
HandlerTimeout time.Duration
// ShutdownTimeout bounds Shutdown when the caller's context has no
// deadline of its own. Defaults to 30s.
ShutdownTimeout time.Duration
HookTimeout time.Duration
TrustedProxies []string
ErrorHandler ErrorHandler
Validator Validator
Health *HealthConfig
Docs *DocsConfig
Logger Logger
}
Config holds app-level settings.
Timeout semantics: 0 means "use the safe default" where one exists, a negative value disables the timeout entirely.
type Controller ¶
type Controller interface {
Routes() []Route
}
Controller is the interface every controller must satisfy. Routes() declares the handler mappings. That is the only contract.
type Ctx ¶
Ctx is the request context passed to every Bast handler. Pooled via sync.Pool — reset and reused after every request.
CRITICAL: *Ctx does NOT implement context.Context intentionally. This means you cannot pass *Ctx where context.Context is expected. The compiler enforces correct usage, always call ctx.Context() for passing to services, goroutines, or DB calls.
func BenchAcquireCtx ¶
func BenchAcquireCtx(w http.ResponseWriter, r *http.Request) *Ctx
BenchAcquireCtx and BenchReleaseCtx expose the pool for benchmark tests.
func NewTestCtxWithPath ¶
NewTestCtxWithPath builds a test Ctx with a specific URL path set.
func (*Ctx) Bind ¶
Bind decodes and validates the request body into v. Returns a 400 BastError on malformed JSON, or a ValidationError on failed struct validation — both flow cleanly through the error boundary.
func (*Ctx) BindForm ¶
BindForm binds a url-encoded or multipart form into a struct pointer. Fields are matched by their `form:"name"` tag, falling back to the field name. A tag of "-" skips the field. Uses reflection — never on the hot path.
Supported field types: string, the signed/unsigned integer kinds, float32/64, bool, time.Duration, and []string (repeated form values). Invalid input yields a 400 BastError so it flows through the error boundary. Values populated by FormValue's r.Form (query + POST body) are used; multipart file parts are read via File/Files, not here.
func (*Ctx) BindJSON ¶
BindJSON decodes JSON body into v without running validation. Returns a 400 BastError on malformed JSON so the error boundary produces a proper Bad Request response instead of a 500.
func (*Ctx) File ¶
func (c *Ctx) File(field string) (*multipart.FileHeader, error)
File retrieves a single uploaded file by field name.
func (*Ctx) Files ¶
func (c *Ctx) Files(field string) ([]*multipart.FileHeader, error)
Files retrieves multiple uploaded files from one field.
func (*Ctx) IP ¶
IP returns the real client IP, respecting X-Forwarded-For and X-Real-IP only when the request comes from a trusted proxy.
X-Forwarded-For is walked right to left: each proxy appends the address it saw, so the rightmost entry NOT itself a trusted proxy is the real client. The leftmost entries are attacker-controlled — a client can send a forged XFF header and a trusted proxy will simply append the truth after it.
func (*Ctx) MustGet ¶
MustGet retrieves a value and panics if not found. Use only when a guard guarantees the value was set.
func (*Ctx) Paginated ¶
func (c *Ctx) Paginated(data any, meta PaginationMeta) Response
Paginated returns a 200 response with data and pagination metadata.
func (*Ctx) QueryDefault ¶
QueryDefault returns a query param or a fallback if missing.
func (*Ctx) RawBody ¶
RawBody reads and returns the request body bytes. Safe to call multiple times. The slice is backed by a pooled buffer: valid until the handler returns, copy it if you need to retain it longer.
func (*Ctx) WithCookie ¶
WithCookie chains a cookie onto a response.
type Doc ¶
type Doc struct {
Summary string
Description string
Tags []string
Params []Param
Body *BodySchema
Returns Returns
Deprecated bool
DeprecatedMsg string
}
Doc holds human-readable documentation for a route, used to build OpenAPI specs.
type DocsConfig ¶
type DocsConfig struct {
Enabled bool
Path string // Swagger UI path, e.g. "/docs"
JSONPath string // Raw OpenAPI JSON path, e.g. "/openapi.json"
Title string
Version string
Description string
// AssetsBaseURL is where the Swagger UI css/js load from. Defaults to the
// unpkg CDN; point it at a self-hosted copy (e.g. "/static/swagger") for
// air-gapped or supply-chain-sensitive deployments.
AssetsBaseURL string
}
DocsConfig configures the built-in OpenAPI documentation endpoints.
type ErrorHandler ¶
ErrorHandler maps an error to a Response.
type Guard ¶
Guard is a pre-handler check. Return nil to allow, return an error to block. Guards run before the handler and short-circuit on the first non-nil error.
type HandlerFunc ¶
HandlerFunc is the signature every Bast handler must have. No variadic args, no interface{}, no side effects.
type HealthCheck ¶
type HealthCheck struct {
Name string
// contains filtered or unexported fields
}
HealthCheck is a named dependency check run on the readiness endpoint.
func CustomCheck ¶
func CustomCheck(name string, fn func(ctx context.Context) error) HealthCheck
CustomCheck builds a HealthCheck from a name and a check function.
type HealthConfig ¶
type HealthConfig struct {
LivePath string // liveness probe path, e.g. "/health"
ReadyPath string // readiness probe path, e.g. "/ready"
Checks []HealthCheck // dependency checks run on /ready
}
HealthConfig configures the built-in health check endpoints.
type Hooks ¶
type Hooks interface {
OnInit(ctx context.Context) error
OnReady()
OnShutdown(ctx context.Context) error
}
Hooks is an optional interface modules may implement to hook into the app lifecycle.
type Logger ¶
type Logger interface {
OnBoot(version string)
OnModuleRegistered(name, prefix string)
OnRouteRegistered(method, path string, guards []string)
OnServiceExported(serviceType string, fromModule string)
OnServiceResolved(serviceType string, toModule string)
OnListening(port int)
OnShutdown()
OnRequest(method, path string, status int, dur time.Duration, ip string)
OnError(ctx *Ctx, err error)
Info(msg string, args ...any)
Warn(msg string, args ...any)
Error(msg string, args ...any)
Debug(msg string, args ...any)
}
Logger is the pluggable logging interface for the Bast framework. The default implementation produces colored output to stdout. Swap it out via Config.Logger for Zap, Zerolog, or any other backend.
func NewDefaultLogger ¶
func NewDefaultLogger() Logger
NewDefaultLogger returns the default Bast logger writing to stdout.
type MiddlewareFunc ¶
type MiddlewareFunc func(next HandlerFunc) HandlerFunc
MiddlewareFunc wraps a HandlerFunc to form a pipeline. Call next(ctx) to pass control to the next middleware or handler. Do not call next to short-circuit (e.g. auth failure) — return a Response directly.
type Module ¶
type Module struct {
// Prefix is the URL prefix for all routes in this module.
Prefix string
// Controller declares this module's routes.
Controller Controller
// Middleware scoped to every route in this module.
// Runs after global middleware, before route-level middleware.
Middleware []MiddlewareFunc
// Guards scoped to every route in this module.
// Runs after global guards, before route-level guards.
Guards []Guard
// Nested sub-modules. Inherits parent prefix.
Modules []Module
// Doc metadata for Swagger tag group.
Doc ModuleDoc
}
Module is a portable, self-contained unit of functionality. It owns its routes, guards, middleware, and optionally sub-modules.
type PaginationMeta ¶
type PaginationMeta struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
Total int `json:"total"`
Pages int `json:"pages"`
}
PaginationMeta holds standard pagination information.
type Param ¶
type Param struct {
In string // "path", "query", "header"
Name string
Description string
Required bool
}
Param describes a single route parameter for OpenAPI docs.
func QueryParam ¶
QueryParam constructs a query parameter descriptor.
type Response ¶
type Response struct {
// contains filtered or unexported fields
}
Response is an immutable value representing what the framework should write. Constructed via Ctx methods — never directly instantiated by user code. All methods use value receivers and return new Response values — never mutate.
Internal constructors below are used by Ctx methods and basttest.
func DefaultErrorHandler ¶
DefaultErrorHandler is the built-in error boundary. Maps BastError and ValidationError to structured JSON responses. Unknown errors become 500 without leaking internals.
func NewErrorResponse ¶
NewErrorResponse is the exported form used by basttest and response tests.
func NewRawResponse ¶
NewRawResponse is the exported form used by basttest and response tests.
func (Response) ContentType ¶
ContentType returns the Content-Type header value.
func (Response) Headers ¶
Headers returns the response headers as a map. Built lazily — not called on the hot path. Returns nil when no headers have been set.
func (Response) WithCookie ¶
WithCookie returns a new Response with an additional cookie attached.
func (Response) WithHeader ¶
WithHeader returns a new Response with an additional header set. Allocates a new backing slice of exactly len+1 — no capacity aliasing possible. Strips \r and \n from both key and value to prevent CRLF injection.
func (Response) WithStatus ¶
WithStatus returns a new Response with a different status code.
type Returns ¶
type Returns map[int]*BodySchema
Returns maps HTTP status codes to response body schemas.
type Route ¶
type Route struct {
Method string
Pattern string
Handler HandlerFunc
Stream StreamHandlerFunc // non-nil when this is a streaming route
Middleware []MiddlewareFunc
Guards []Guard
Timeout time.Duration
MaxBodySize int64
Doc Doc
}
Route binds an HTTP method + path pattern to a handler.
func DELETE ¶
func DELETE(pattern string, handler HandlerFunc, opts ...RouteOption) Route
DELETE constructs a DELETE route.
func GET ¶
func GET(pattern string, handler HandlerFunc, opts ...RouteOption) Route
GET constructs a GET route.
func PATCH ¶
func PATCH(pattern string, handler HandlerFunc, opts ...RouteOption) Route
PATCH constructs a PATCH route.
func POST ¶
func POST(pattern string, handler HandlerFunc, opts ...RouteOption) Route
POST constructs a POST route.
func PUT ¶
func PUT(pattern string, handler HandlerFunc, opts ...RouteOption) Route
PUT constructs a PUT route.
func STREAM ¶
func STREAM(pattern string, handler StreamHandlerFunc, opts ...RouteOption) Route
STREAM constructs a streaming route. The handler owns the connection for its lifetime.
type RouteOption ¶
type RouteOption func(*Route)
RouteOption applies optional config to a route at construction time.
func WithGuards ¶
func WithGuards(guards ...Guard) RouteOption
WithGuards attaches guards to a specific route.
func WithMaxBody ¶
func WithMaxBody(n int64) RouteOption
WithMaxBody sets a per-route request body size limit in bytes.
func WithMiddleware ¶
func WithMiddleware(mw ...MiddlewareFunc) RouteOption
WithMiddleware attaches middleware to a specific route.
func WithTimeout ¶
func WithTimeout(d time.Duration) RouteOption
WithTimeout sets a per-route handler timeout.
type SecuredGuard ¶
type SecuredGuard interface {
Guard
SecurityScheme() SecurityScheme
}
SecuredGuard is a Guard that also declares its OpenAPI security scheme. Bast uses this to populate securitySchemes in the OpenAPI spec automatically.
type SecurityScheme ¶
type SecurityScheme struct {
Type string // "http", "apiKey", "oauth2"
Scheme string // "bearer", "basic"
BearerFormat string // "JWT"
Description string
}
SecurityScheme describes an OpenAPI security scheme declared by a guard.
type StreamCtx ¶
type StreamCtx struct {
context.Context
Request *http.Request
// contains filtered or unexported fields
}
StreamCtx is the context for streaming handlers.
Unlike *Ctx it is intentionally NOT pooled. Stream connections are long-lived (seconds to hours), so their lifetime is unbounded and cannot be managed by a sync.Pool: the pool would either hold the slot indefinitely (defeating the pool) or return the object while the connection is still active (use-after-free). One allocation per connection is negligible compared to the cost of keeping the connection open. GC handles reclamation naturally when Done fires and the handler returns.
It embeds context.Context directly — safe to pass anywhere, for any duration.
func NewTestStreamCtx ¶ added in v0.2.0
func NewTestStreamCtx() *StreamCtx
NewTestStreamCtx creates a StreamCtx outside the pool for unit testing stream handlers. Never pool or reuse a test StreamCtx.
func (*StreamCtx) Closed ¶
func (s *StreamCtx) Closed() <-chan struct{}
Closed returns a channel that is closed when the client disconnects. Equivalent to StreamCtx.Done() via the embedded context.
func (*StreamCtx) Flush ¶
Flush flushes buffered data to the client immediately. Returns an error if the underlying write fails (e.g. client disconnected).
func (*StreamCtx) Get ¶ added in v0.2.0
Get retrieves a value from the request-scoped store. Values are populated by guards that ran before the stream handler.
func (*StreamCtx) MustGet ¶ added in v0.2.0
MustGet retrieves a value and panics if not found. Use only when a guard guarantees the value was set.
func (*StreamCtx) Param ¶ added in v0.2.0
Param returns a URL path parameter by name. e.g. STREAM("/:id/events", ...) → sctx.Param("id") == "42" for /42/events
func (*StreamCtx) Send ¶
Send writes a Server-Sent Event to the client.
The event name has CR/LF stripped and multi-line data is emitted as one "data:" line per payload line (EventSource rejoins them with \n), so user-supplied text can never forge extra SSE frames.
func (*StreamCtx) SetHeader ¶
SetHeader sets a response header. Must be called before first Write or Send.
type StreamHandlerFunc ¶
type StreamHandlerFunc func(ctx *StreamCtx)
StreamHandlerFunc is the signature for streaming handlers. Does not return a Response, the handler owns the wire for its full duration.
type ValidationError ¶
ValidationError is returned by ctx.Bind() when struct validation fails. The error boundary detects it and produces field-level 422 responses automatically.
func (*ValidationError) BastStatus ¶
func (e *ValidationError) BastStatus() int
BastStatus satisfies a convention checked by the error boundary.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
func (*ValidationError) JSON ¶
func (e *ValidationError) JSON() []byte
JSON serializes ValidationError into the validation error envelope.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package basttest provides test helpers for Bast handlers and apps.
|
Package basttest provides test helpers for Bast handlers and apps. |
|
cmd
|
|
|
bast
command
|
|
|
internal
|
|
|
jsonx
Package jsonx is the single seam between bast and its JSON backend.
|
Package jsonx is the single seam between bast and its JSON backend. |