Documentation ¶
Overview ¶
Package nexus provides client and server implementations of the Nexus HTTP API
Index ¶
- Constants
- Variables
- func ExecuteOperation[I, O any](ctx context.Context, client *HTTPClient, operation OperationReference[I, O], ...) (O, error)
- func NewCompletionHTTPHandler(options CompletionHandlerOptions) http.Handler
- func NewCompletionHTTPRequest(ctx context.Context, url string, completion OperationCompletion) (*http.Request, error)
- func NewHTTPHandler(options HandlerOptions) http.Handler
- type CancelOperationOptions
- type ClientStartOperationResult
- type CompletionHandler
- type CompletionHandlerOptions
- type CompletionRequest
- type Content
- type ExecuteOperationOptions
- type Failure
- type FailureConverter
- type FailureError
- type GetOperationInfoOptions
- type GetOperationResultOptions
- type HTTPClient
- func (c *HTTPClient) ExecuteOperation(ctx context.Context, operation string, input any, ...) (*LazyValue, error)
- func (c *HTTPClient) NewHandle(operation string, operationID string) (*OperationHandle[*LazyValue], error)
- func (c *HTTPClient) StartOperation(ctx context.Context, operation string, input any, ...) (*ClientStartOperationResult[*LazyValue], error)
- type HTTPClientOptions
- type Handler
- type HandlerError
- type HandlerErrorType
- type HandlerOptions
- type HandlerStartOperationResult
- type HandlerStartOperationResultAsync
- type HandlerStartOperationResultSync
- type Header
- type LazyValue
- type Link
- type NoValue
- type Operation
- type OperationCompletion
- type OperationCompletionSuccessful
- type OperationCompletionSuccessfulOptions
- type OperationCompletionUnsuccessful
- type OperationCompletionUnsuccessfulOptions
- type OperationHandle
- func (h *OperationHandle[T]) Cancel(ctx context.Context, options CancelOperationOptions) error
- func (h *OperationHandle[T]) GetInfo(ctx context.Context, options GetOperationInfoOptions) (*OperationInfo, error)
- func (h *OperationHandle[T]) GetResult(ctx context.Context, options GetOperationResultOptions) (T, error)
- type OperationInfo
- type OperationReference
- type OperationState
- type Reader
- type RegisterableOperation
- type Serializer
- type Service
- type ServiceRegistry
- type StartOperationOptions
- type UnexpectedResponseError
- type UnimplementedHandler
- func (h UnimplementedHandler) CancelOperation(ctx context.Context, service, operation, operationID string, ...) error
- func (h UnimplementedHandler) GetOperationInfo(ctx context.Context, service, operation, operationID string, ...) (*OperationInfo, error)
- func (h UnimplementedHandler) GetOperationResult(ctx context.Context, service, operation, operationID string, ...) (any, error)
- func (h UnimplementedHandler) StartOperation(ctx context.Context, service, operation string, input *LazyValue, ...) (HandlerStartOperationResult[any], error)
- type UnimplementedOperation
- func (*UnimplementedOperation[I, O]) Cancel(context.Context, string, CancelOperationOptions) error
- func (*UnimplementedOperation[I, O]) GetInfo(context.Context, string, GetOperationInfoOptions) (*OperationInfo, error)
- func (*UnimplementedOperation[I, O]) GetResult(context.Context, string, GetOperationResultOptions) (O, error)
- func (*UnimplementedOperation[I, O]) InputType() reflect.Type
- func (*UnimplementedOperation[I, O]) OutputType() reflect.Type
- func (h *UnimplementedOperation[I, O]) Start(ctx context.Context, input I, options StartOperationOptions) (HandlerStartOperationResult[O], error)
- type UnsuccessfulOperationError
Examples ¶
Constants ¶
const ( // HeaderOperationID is the unique ID returned by the StartOperation response for async operations. // Must be set on callback headers to support completing operations before the start response is received. HeaderOperationID = "nexus-operation-id" // HeaderRequestTimeout is the total time to complete a Nexus HTTP request. HeaderRequestTimeout = "request-timeout" // HeaderOperationTimeout is the total time to complete a Nexus operation. // Unlike HeaderRequestTimeout, this applies to the whole operation, not just a single HTTP request. HeaderOperationTimeout = "operation-timeout" )
const (
StatusUpstreamTimeout = 520
)
Variables ¶
var ErrOperationStillRunning = errors.New("operation still running")
ErrOperationStillRunning indicates that an operation is still running while trying to get its result.
Functions ¶
func ExecuteOperation ¶ added in v0.0.2
func ExecuteOperation[I, O any](ctx context.Context, client *HTTPClient, operation OperationReference[I, O], input I, request ExecuteOperationOptions) (O, error)
ExecuteOperation is the type safe version of HTTPClient.ExecuteOperation. It accepts input of type I and returns output of type O, removing the need to consume the LazyValue returned by the client method.
ref := NewOperationReference[MyInput, MyOutput]("my-operation") out, err := ExecuteOperation(ctx, client, ref, MyInput{}, options) // returns MyOutput, error
func NewCompletionHTTPHandler ¶
func NewCompletionHTTPHandler(options CompletionHandlerOptions) http.Handler
NewCompletionHTTPHandler constructs an http.Handler from given options for handling operation completion requests.
func NewCompletionHTTPRequest ¶
func NewCompletionHTTPRequest(ctx context.Context, url string, completion OperationCompletion) (*http.Request, error)
NewCompletionHTTPRequest creates an HTTP request deliver an operation completion to a given URL.
func NewHTTPHandler ¶
func NewHTTPHandler(options HandlerOptions) http.Handler
NewHTTPHandler constructs an http.Handler from given options for handling Nexus service requests.
Types ¶
type CancelOperationOptions ¶
type CancelOperationOptions struct { // Header contains the request header fields either received by the server or to be sent by the client. // // Header will always be non empty in server methods and can be optionally set in the client API. // // Header values set here will overwrite any SDK-provided values for the same key. Header Header }
CancelOperationOptions are options for the CancelOperation client and server APIs.
type ClientStartOperationResult ¶ added in v0.0.2
type ClientStartOperationResult[T any] struct { // Set when start completes synchronously and successfully. // // If T is a [LazyValue], ensure that your consume it or read the underlying content in its entirety and close it to // free up the underlying connection. Successful T // Set when the handler indicates that it started an asynchronous operation. // The attached handle can be used to perform actions such as cancel the operation or get its result. Pending *OperationHandle[T] // Links contain information about the operations done by the handler. Links []Link }
ClientStartOperationResult is the return type of HTTPClient.StartOperation. One and only one of Successful or Pending will be non-nil.
func StartOperation ¶ added in v0.0.2
func StartOperation[I, O any](ctx context.Context, client *HTTPClient, operation OperationReference[I, O], input I, request StartOperationOptions) (*ClientStartOperationResult[O], error)
StartOperation is the type safe version of HTTPClient.StartOperation. It accepts input of type I and returns a ClientStartOperationResult of type O, removing the need to consume the LazyValue returned by the client method.
type CompletionHandler ¶
type CompletionHandler interface {
CompleteOperation(context.Context, *CompletionRequest) error
}
A CompletionHandler can receive operation completion requests as delivered via the callback URL provided in start-operation requests.
type CompletionHandlerOptions ¶
type CompletionHandlerOptions struct { // Handler for completion requests. Handler CompletionHandler // A stuctured logging handler. // Defaults to slog.Default(). Logger *slog.Logger // A [Serializer] to customize handler serialization behavior. // By default the handler handles, JSONables, byte slices, and nil. Serializer Serializer // A [FailureConverter] to convert a [Failure] instance to and from an [error]. Defaults to // [DefaultFailureConverter]. FailureConverter FailureConverter }
CompletionHandlerOptions are options for NewCompletionHTTPHandler.
type CompletionRequest ¶
type CompletionRequest struct { // The original HTTP request. HTTPRequest *http.Request // State of the operation. State OperationState // OperationID is the ID of the operation. Used when a completion callback is received before a started response. OperationID string // StartTime is the time the operation started. Used when a completion callback is received before a started response. StartTime time.Time // Links are used to link back to the operation when a completion callback is received before a started response. Links []Link // Parsed from request and set if State is failed or canceled. Error error // Extracted from request and set if State is succeeded. Result *LazyValue }
CompletionRequest is input for CompletionHandler.CompleteOperation.
type Content ¶ added in v0.0.2
type Content struct { // Header that should include information on how to deserialize this content. // Headers constructed by the framework always have lower case keys. // User provided keys are considered case-insensitive by the framework. Header Header // Data contains request or response data. May be nil for empty data. Data []byte }
A Content is a container for a Header and a byte slice. It is used by the SDK's Serializer interface implementations.
type ExecuteOperationOptions ¶
type ExecuteOperationOptions struct { // Callback URL to provide to the handle for receiving async operation completions. Optional. // Even though Client.ExecuteOperation waits for operation completion, some applications may want to set this // callback as a fallback mechanism. CallbackURL string // Optional header fields set by a client that are required to be attached to the callback request when an // asynchronous operation completes. CallbackHeader Header // Request ID that may be used by the server handler to dedupe this start request. // By default a v4 UUID will be generated by the client. RequestID string // Links contain arbitrary caller information. Handlers may use these links as // metadata on resources associated with and operation. Links []Link // Header to attach to start and get-result requests. Optional. // // Header values set here will overwrite any SDK-provided values for the same key. // // Header keys with the "content-" prefix are reserved for [Serializer] headers and should not be set in the // client API; they are not available to server [Handler] and [Operation] implementations. Header Header // Duration to wait for operation completion. // // ⚠ NOTE: unlike GetOperationResultOptions.Wait, zero and negative values are considered effectively infinite. Wait time.Duration }
ExecuteOperationOptions are options for HTTPClient.ExecuteOperation.
type Failure ¶
type Failure struct { // A simple text message. Message string `json:"message"` // A key-value mapping for additional context. Useful for decoding the 'details' field, if needed. Metadata map[string]string `json:"metadata,omitempty"` // Additional JSON serializable structured data. Details json.RawMessage `json:"details,omitempty"` }
A Failure represents failed handler invocations as well as `failed` or `canceled` operation results. Failures shouldn't typically be constructed directly. The SDK APIs take a FailureConverter instance that can translate language errors to and from Failure instances.
type FailureConverter ¶ added in v0.1.0
type FailureConverter interface { // ErrorToFailure converts an [error] to a [Failure]. // Implementors should take a best-effort approach and never fail this method. // Note that the provided error may be nil. ErrorToFailure(error) Failure // ErrorToFailure converts a [Failure] to an [error]. // Implementors should take a best-effort approach and never fail this method. FailureToError(Failure) error }
FailureConverter is used by the framework to transform [error] instances to and from Failure instances. To customize conversion logic, implement this interface and provide your implementation to framework methods such as [NewClient] and NewHTTPHandler. By default the SDK translates only error messages, losing type information and struct fields.
func DefaultFailureConverter ¶ added in v0.1.0
func DefaultFailureConverter() FailureConverter
DefaultFailureConverter returns the SDK's default FailureConverter implementation. Arbitrary errors are converted to a simple Failure object with just the Message popluated and FailureError instances to their underlying Failure instance. Failure instances are converted to FailureError to allow access to the full failure metadata and details if available.
type FailureError ¶ added in v0.1.0
type FailureError struct { // The underlying Failure object this error represents. Failure Failure }
An error that directly represents a wire representation of Failure. The SDK will convert to this error by default unless the FailureConverter instance is customized.
func (*FailureError) Error ¶ added in v0.1.0
func (e *FailureError) Error() string
Error implements the error interface.
type GetOperationInfoOptions ¶
type GetOperationInfoOptions struct { // Header contains the request header fields either received by the server or to be sent by the client. // // Header will always be non empty in server methods and can be optionally set in the client API. // // Header values set here will overwrite any SDK-provided values for the same key. Header Header }
GetOperationInfoOptions are options for the GetOperationInfo client and server APIs.
type GetOperationResultOptions ¶
type GetOperationResultOptions struct { // Header contains the request header fields either received by the server or to be sent by the client. // // Header will always be non empty in server methods and can be optionally set in the client API. // // Header values set here will overwrite any SDK-provided values for the same key. Header Header // If non-zero, reflects the duration the caller has indicated that it wants to wait for operation completion, // turning the request into a long poll. Wait time.Duration }
GetOperationResultOptions are options for the GetOperationResult client and server APIs.
type HTTPClient ¶ added in v0.1.0
type HTTPClient struct {
// contains filtered or unexported fields
}
An HTTPClient makes Nexus service requests as defined in the Nexus HTTP API.
It can start a new operation and get an OperationHandle to an existing, asynchronous operation.
Use an OperationHandle to cancel, get the result of, and get information about asynchronous operations.
OperationHandles can be obtained either by starting new operations or by calling HTTPClient.NewHandle for existing operations.
func NewHTTPClient ¶ added in v0.1.0
func NewHTTPClient(options HTTPClientOptions) (*HTTPClient, error)
NewHTTPClient creates a new HTTPClient from provided HTTPClientOptions. BaseURL and Service are required.
func (*HTTPClient) ExecuteOperation ¶ added in v0.1.0
func (c *HTTPClient) ExecuteOperation(ctx context.Context, operation string, input any, options ExecuteOperationOptions) (*LazyValue, error)
ExecuteOperation is a helper for starting an operation and waiting for its completion.
For asynchronous operations, the client will long poll for their result, issuing one or more requests until the wait period provided via ExecuteOperationOptions exceeds, in which case an ErrOperationStillRunning error is returned.
The wait time is capped to the deadline of the provided context. Make sure to handle both context deadline errors and ErrOperationStillRunning.
Note that the wait period is enforced by the server and may not be respected if the server is misbehaving. Set the context deadline to the max allowed wait period to ensure this call returns in a timely fashion.
⚠️ If this method completes successfully, the returned response's body must be read in its entirety and closed to free up the underlying connection.
Example ¶
package main import ( "context" "fmt" "github.com/nexus-rpc/sdk-go/nexus" ) type MyStruct struct { Field string } var ctx = context.Background() var client *nexus.HTTPClient func main() { response, err := client.ExecuteOperation(ctx, "operation name", MyStruct{Field: "value"}, nexus.ExecuteOperationOptions{}) if err != nil { // handle nexus.UnsuccessfulOperationError, nexus.ErrOperationStillRunning and, context.DeadlineExceeded } // must close the returned response body and read it until EOF to free up the underlying connection var output MyStruct _ = response.Consume(&output) fmt.Printf("Got response: %v\n", output) }
Output:
func (*HTTPClient) NewHandle ¶ added in v0.1.0
func (c *HTTPClient) NewHandle(operation string, operationID string) (*OperationHandle[*LazyValue], error)
NewHandle gets a handle to an asynchronous operation by name and ID. Does not incur a trip to the server. Fails if provided an empty operation or ID.
func (*HTTPClient) StartOperation ¶ added in v0.1.0
func (c *HTTPClient) StartOperation( ctx context.Context, operation string, input any, options StartOperationOptions, ) (*ClientStartOperationResult[*LazyValue], error)
StartOperation calls the configured Nexus endpoint to start an operation.
This method has the following possible outcomes:
The operation completes successfully. The result of this call will be set as a LazyValue in ClientStartOperationResult.Successful and must be consumed to free up the underlying connection.
The operation was started and the handler has indicated that it will complete asynchronously. An OperationHandle will be returned as ClientStartOperationResult.Pending, which can be used to perform actions such as getting its result.
The operation was unsuccessful. The returned result will be nil and error will be an UnsuccessfulOperationError.
Any other error.
Example ¶
package main import ( "context" "errors" "fmt" "github.com/nexus-rpc/sdk-go/nexus" ) type MyStruct struct { Field string } var ctx = context.Background() var client *nexus.HTTPClient func main() { result, err := client.StartOperation(ctx, "example", MyStruct{Field: "value"}, nexus.StartOperationOptions{}) if err != nil { var unsuccessfulOperationError *nexus.UnsuccessfulOperationError if errors.As(err, &unsuccessfulOperationError) { // operation failed or canceled fmt.Printf("Operation unsuccessful with state: %s, failure message: %s\n", unsuccessfulOperationError.State, unsuccessfulOperationError.Cause.Error()) } var handlerError *nexus.HandlerError if errors.As(err, &handlerError) { fmt.Printf("Handler returned an error, type: %s, failure message: %s\n", handlerError.Type, handlerError.Cause.Error()) } // most other errors should be returned as *nexus.UnexpectedResponseError } if result.Successful != nil { // operation successful response := result.Successful // must consume the response to free up the underlying connection var output MyStruct _ = response.Consume(&output) fmt.Printf("Got response: %v\n", output) } else { // operation started asynchronously handle := result.Pending fmt.Printf("Started asynchronous operation with ID: %s\n", handle.ID) } }
Output:
type HTTPClientOptions ¶ added in v0.1.0
type HTTPClientOptions struct { // Base URL for all requests. Required. BaseURL string // Service name. Required. Service string // A function for making HTTP requests. // Defaults to [http.DefaultClient.Do]. HTTPCaller func(*http.Request) (*http.Response, error) // A [Serializer] to customize client serialization behavior. // By default the client handles JSONables, byte slices, and nil. Serializer Serializer // A [FailureConverter] to convert a [Failure] instance to and from an [error]. Defaults to // [DefaultFailureConverter]. FailureConverter FailureConverter }
HTTPClientOptions are options for creating an HTTPClient.
type Handler ¶
type Handler interface { // StartOperation handles requests for starting an operation. Return [HandlerStartOperationResultSync] to // respond successfully - inline, or [HandlerStartOperationResultAsync] to indicate that an asynchronous // operation was started. Return an [UnsuccessfulOperationError] to indicate that an operation completed as // failed or canceled. StartOperation(ctx context.Context, service, operation string, input *LazyValue, options StartOperationOptions) (HandlerStartOperationResult[any], error) // GetOperationResult handles requests to get the result of an asynchronous operation. Return non error result // to respond successfully - inline, or error with [ErrOperationStillRunning] to indicate that an asynchronous // operation is still running. Return an [UnsuccessfulOperationError] to indicate that an operation completed as // failed or canceled. // // When [GetOperationResultOptions.Wait] is greater than zero, this request should be treated as a long poll. // Long poll requests have a server side timeout, configurable via [HandlerOptions.GetResultTimeout], and exposed // via context deadline. The context deadline is decoupled from the application level Wait duration. // // It is the implementor's responsiblity to respect the client's wait duration and return in a timely fashion. // Consider using a derived context that enforces the wait timeout when implementing this method and return // [ErrOperationStillRunning] when that context expires as shown in the example. GetOperationResult(ctx context.Context, service, operation, operationID string, options GetOperationResultOptions) (any, error) // GetOperationInfo handles requests to get information about an asynchronous operation. GetOperationInfo(ctx context.Context, service, operation, operationID string, options GetOperationInfoOptions) (*OperationInfo, error) // CancelOperation handles requests to cancel an asynchronous operation. // Cancelation in Nexus is: // 1. asynchronous - returning from this method only ensures that cancelation is delivered, it may later be // ignored by the underlying operation implemention. // 2. idempotent - implementors should ignore duplicate cancelations for the same operation. CancelOperation(ctx context.Context, service, operation, operationID string, options CancelOperationOptions) error // contains filtered or unexported methods }
A Handler must implement all of the Nexus service endpoints as defined in the Nexus HTTP API.
Handler implementations must embed the UnimplementedHandler.
All Handler methods can return a HandlerError to fail requests with a custom HandlerErrorType and structured Failure. Arbitrary errors from handler methods are turned into HandlerErrorTypeInternal,their details are logged and hidden from the caller.
Example ¶
package main import ( "context" "net" "net/http" "time" "github.com/nexus-rpc/sdk-go/nexus" ) type myHandler struct { nexus.UnimplementedHandler } type MyResult struct { Field string `json:"field"` } // StartOperation implements the Handler interface. func (h *myHandler) StartOperation(ctx context.Context, service, operation string, input *nexus.LazyValue, options nexus.StartOperationOptions) (nexus.HandlerStartOperationResult[any], error) { if err := h.authorize(ctx, options.Header); err != nil { return nil, err } return &nexus.HandlerStartOperationResultAsync{OperationID: "meaningful-id"}, nil } // GetOperationResult implements the Handler interface. func (h *myHandler) GetOperationResult(ctx context.Context, service, operation, operationID string, options nexus.GetOperationResultOptions) (any, error) { if err := h.authorize(ctx, options.Header); err != nil { return nil, err } if options.Wait > 0 { // request is a long poll var cancel context.CancelFunc ctx, cancel = context.WithTimeout(ctx, options.Wait) defer cancel() result, err := h.pollOperation(ctx, options.Wait) if err != nil { // Translate deadline exceeded to "OperationStillRunning", this may or may not be semantically correct for // your application. // Some applications may want to "peek" the current status instead of performing this blind conversion if // the wait time is exceeded and the request's context deadline has not yet exceeded. if ctx.Err() != nil { return nil, nexus.ErrOperationStillRunning } // Optionally translate to operation failure (could also result in canceled state). // Optionally expose the error details to the caller. return nil, nexus.NewFailedOperationError(err) } return result, nil } else { result, err := h.peekOperation(ctx) if err != nil { // Optionally translate to operation failure (could also result in canceled state). return nil, nexus.NewFailedOperationError(err) } return result, nil } } func (h *myHandler) CancelOperation(ctx context.Context, service, operation, operationID string, options nexus.CancelOperationOptions) error { // Handlers must implement this. panic("unimplemented") } func (h *myHandler) GetOperationInfo(ctx context.Context, service, operation, operationID string, options nexus.GetOperationInfoOptions) (*nexus.OperationInfo, error) { // Handlers must implement this. panic("unimplemented") } func (h *myHandler) pollOperation(ctx context.Context, wait time.Duration) (*MyResult, error) { panic("unimplemented") } func (h *myHandler) peekOperation(ctx context.Context) (*MyResult, error) { panic("unimplemented") } func (h *myHandler) authorize(_ context.Context, header nexus.Header) error { // Authorization for demo purposes if header.Get("Authorization") != "Bearer top-secret" { return nexus.HandlerErrorf(nexus.HandlerErrorTypeUnauthorized, "unauthorized") } return nil } func main() { handler := &myHandler{} httpHandler := nexus.NewHTTPHandler(nexus.HandlerOptions{Handler: handler}) listener, _ := net.Listen("tcp", "localhost:0") defer listener.Close() _ = http.Serve(listener, httpHandler) }
Output:
type HandlerError ¶
type HandlerError struct { // Error Type. Defaults to HandlerErrorTypeInternal. Type HandlerErrorType // The underlying cause for this error. Cause error }
HandlerError is a special error that can be returned from Handler methods for failing a request with a custom status code and failure message.
func HandlerErrorf ¶ added in v0.0.2
func HandlerErrorf(typ HandlerErrorType, format string, args ...any) *HandlerError
HandlerErrorf creates a HandlerError with the given type using fmt.Errorf to construct the cause.
func (*HandlerError) Error ¶
func (e *HandlerError) Error() string
Error implements the error interface.
func (*HandlerError) Unwrap ¶ added in v0.1.0
func (e *HandlerError) Unwrap() error
Unwrap returns the cause for use with utilities in the errors package.
type HandlerErrorType ¶ added in v0.0.2
type HandlerErrorType string
const ( // The server cannot or will not process the request due to an apparent client error. HandlerErrorTypeBadRequest HandlerErrorType = "BAD_REQUEST" // The client did not supply valid authentication credentials for this request. HandlerErrorTypeUnauthenticated HandlerErrorType = "UNAUTHENTICATED" HandlerErrorTypeUnauthorized HandlerErrorType = "UNAUTHORIZED" // The requested resource could not be found but may be available in the future. Subsequent requests by the client // are permissible. HandlerErrorTypeNotFound HandlerErrorType = "NOT_FOUND" // Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space. HandlerErrorTypeResourceExhausted HandlerErrorType = "RESOURCE_EXHAUSTED" // An internal error occured. HandlerErrorTypeInternal HandlerErrorType = "INTERNAL" // The server either does not recognize the request method, or it lacks the ability to fulfill the request. HandlerErrorTypeNotImplemented HandlerErrorType = "NOT_IMPLEMENTED" HandlerErrorTypeUnavailable HandlerErrorType = "UNAVAILABLE" // Used by gateways to report that a request to an upstream server has timed out. HandlerErrorTypeUpstreamTimeout HandlerErrorType = "UPSTREAM_TIMEOUT" )
type HandlerOptions ¶
type HandlerOptions struct { // Handler for handling service requests. Handler Handler // A stuctured logger. // Defaults to slog.Default(). Logger *slog.Logger // Max duration to allow waiting for a single get result request. // Enforced if provided for requests with the wait query parameter set. // // Defaults to one minute. GetResultTimeout time.Duration // A [Serializer] to customize handler serialization behavior. // By default the handler handles JSONables, byte slices, and nil. Serializer Serializer // A [FailureConverter] to convert a [Failure] instance to and from an [error]. // Defaults to [DefaultFailureConverter]. FailureConverter FailureConverter }
HandlerOptions are options for NewHTTPHandler.
type HandlerStartOperationResult ¶ added in v0.0.2
type HandlerStartOperationResult[T any] interface { // contains filtered or unexported methods }
An HandlerStartOperationResult is the return type from the Handler StartOperation and Operation Start methods. It has two implementations: HandlerStartOperationResultSync and HandlerStartOperationResultAsync.
type HandlerStartOperationResultAsync ¶ added in v0.0.2
HandlerStartOperationResultAsync indicates that an operation has been accepted and will complete asynchronously.
type HandlerStartOperationResultSync ¶ added in v0.0.2
type HandlerStartOperationResultSync[T any] struct { Value T }
HandlerStartOperationResultSync indicates that an operation completed successfully.
type Header ¶ added in v0.0.2
Header is a mapping of string to string. It is used throughout the framework to transmit metadata. The keys should be in lower case form.
type LazyValue ¶ added in v0.0.2
type LazyValue struct { Reader *Reader // contains filtered or unexported fields }
A LazyValue holds a value encoded in an underlying Reader.
⚠️ When a LazyValue is returned from a client - if directly accessing the Reader - it must be read it in its entirety and closed to free up the associated HTTP connection. Otherwise the LazyValue.Consume method must be called.
⚠️ When a LazyValue is passed to a server handler, it must not be used after the returning from the handler method.
func NewLazyValue ¶ added in v0.0.8
func NewLazyValue(serializer Serializer, reader *Reader) *LazyValue
Create a new LazyValue from a given serializer and reader.
type Link ¶ added in v0.0.10
type Link struct { // URL information about the link. // It must be URL percent-encoded. URL *url.URL // Type can describe an actual data type for decoding the URL. // Valid chars: alphanumeric, '_', '.', '/' Type string }
Link contains an URL and a Type that can be used to decode the URL. Links can contain any arbitrary information as a percent-encoded URL. It can be used to pass information about the caller to the handler, or vice-versa.
type NoValue ¶ added in v0.0.2
type NoValue *struct{}
NoValue is a marker type for an operations that do not accept any input or return a value (nil).
nexus.NewSyncOperation("my-empty-operation", func(context.Context, nexus.NoValue, options, nexus.StartOperationOptions) (nexus.NoValue, error) { return nil, nil )}
type Operation ¶ added in v0.0.2
type Operation[I, O any] interface { RegisterableOperation OperationReference[I, O] // Start handles requests for starting an operation. Return [HandlerStartOperationResultSync] to respond // successfully - inline, or [HandlerStartOperationResultAsync] to indicate that an asynchronous operation was // started. Return an [UnsuccessfulOperationError] to indicate that an operation completed as failed or // canceled. Start(context.Context, I, StartOperationOptions) (HandlerStartOperationResult[O], error) // GetResult handles requests to get the result of an asynchronous operation. Return non error result to respond // successfully - inline, or error with [ErrOperationStillRunning] to indicate that an asynchronous operation is // still running. Return an [UnsuccessfulOperationError] to indicate that an operation completed as failed or // canceled. // // When [GetOperationResultOptions.Wait] is greater than zero, this request should be treated as a long poll. // Long poll requests have a server side timeout, configurable via [HandlerOptions.GetResultTimeout], and exposed // via context deadline. The context deadline is decoupled from the application level Wait duration. // // It is the implementor's responsiblity to respect the client's wait duration and return in a timely fashion. // Consider using a derived context that enforces the wait timeout when implementing this method and return // [ErrOperationStillRunning] when that context expires as shown in the [Handler] example. GetResult(context.Context, string, GetOperationResultOptions) (O, error) // GetInfo handles requests to get information about an asynchronous operation. GetInfo(context.Context, string, GetOperationInfoOptions) (*OperationInfo, error) // Cancel handles requests to cancel an asynchronous operation. // Cancelation in Nexus is: // 1. asynchronous - returning from this method only ensures that cancelation is delivered, it may later be // ignored by the underlying operation implemention. // 2. idempotent - implementors should ignore duplicate cancelations for the same operation. Cancel(context.Context, string, CancelOperationOptions) error }
Operation is a handler for a single operation.
Operation implementations must embed the UnimplementedOperation.
All Operation methods can return a HandlerError to fail requests with a custom HandlerErrorType and structured Failure. Arbitrary errors from handler methods are turned into HandlerErrorTypeInternal,their details are logged and hidden from the caller.
func NewSyncOperation ¶ added in v0.0.2
func NewSyncOperation[I, O any](name string, handler func(context.Context, I, StartOperationOptions) (O, error)) Operation[I, O]
NewSyncOperation is a helper for creating a synchronous-only Operation from a given name and handler function.
type OperationCompletion ¶
type OperationCompletion interface {
// contains filtered or unexported methods
}
OperationCompletion is input for NewCompletionHTTPRequest. It has two implementations: OperationCompletionSuccessful and OperationCompletionUnsuccessful.
type OperationCompletionSuccessful ¶
type OperationCompletionSuccessful struct { // Header to send in the completion request. // Note that this is a Nexus header, not an HTTP header. Header Header // A [Reader] that may be directly set on the completion or constructed when instantiating via // [NewOperationCompletionSuccessful]. // Automatically closed when the completion is delivered. Reader *Reader // OperationID is the unique ID for this operation. Used when a completion callback is received before a started response. OperationID string // StartTime is the time the operation started. Used when a completion callback is received before a started response. StartTime time.Time // Links are used to link back to the operation when a completion callback is received before a started response. Links []Link }
OperationCompletionSuccessful is input for NewCompletionHTTPRequest, used to deliver successful operation results.
func NewOperationCompletionSuccessful ¶
func NewOperationCompletionSuccessful(result any, options OperationCompletionSuccessfulOptions) (*OperationCompletionSuccessful, error)
NewOperationCompletionSuccessful constructs an OperationCompletionSuccessful from a given result.
type OperationCompletionSuccessfulOptions ¶ added in v0.0.11
type OperationCompletionSuccessfulOptions struct { // Optional serializer for the result. Defaults to the SDK's default Serializer, which handles JSONables, byte // slices and nils. Serializer Serializer // OperationID is the unique ID for this operation. Used when a completion callback is received before a started response. OperationID string // StartTime is the time the operation started. Used when a completion callback is received before a started response. StartTime time.Time // Links are used to link back to the operation when a completion callback is received before a started response. Links []Link }
OperationCompletionSuccessfulOptions are options for NewOperationCompletionSuccessful.
type OperationCompletionUnsuccessful ¶
type OperationCompletionUnsuccessful struct { // Header to send in the completion request. // Note that this is a Nexus header, not an HTTP header. Header Header // State of the operation, should be failed or canceled. State OperationState // OperationID is the unique ID for this operation. Used when a completion callback is received before a started response. OperationID string // StartTime is the time the operation started. Used when a completion callback is received before a started response. StartTime time.Time // Links are used to link back to the operation when a completion callback is received before a started response. Links []Link // Failure object to send with the completion. Failure Failure }
OperationCompletionUnsuccessful is input for NewCompletionHTTPRequest, used to deliver unsuccessful operation results.
func NewOperationCompletionUnsuccessful ¶ added in v0.1.0
func NewOperationCompletionUnsuccessful(error *UnsuccessfulOperationError, options OperationCompletionUnsuccessfulOptions) (*OperationCompletionUnsuccessful, error)
NewOperationCompletionUnsuccessful constructs an OperationCompletionUnsuccessful from a given error.
type OperationCompletionUnsuccessfulOptions ¶ added in v0.1.0
type OperationCompletionUnsuccessfulOptions struct { // A [FailureConverter] to convert a [Failure] instance to and from an [error]. Defaults to // [DefaultFailureConverter]. FailureConverter FailureConverter // OperationID is the unique ID for this operation. Used when a completion callback is received before a started response. OperationID string // StartTime is the time the operation started. Used when a completion callback is received before a started response. StartTime time.Time // Links are used to link back to the operation when a completion callback is received before a started response. Links []Link }
OperationCompletionUnsuccessfulOptions are options for NewOperationCompletionUnsuccessful.
type OperationHandle ¶
type OperationHandle[T any] struct { // Name of the Operation this handle represents. Operation string // Handler generated ID for this handle's operation. ID string // contains filtered or unexported fields }
An OperationHandle is used to cancel operations and get their result and status.
func NewHandle ¶ added in v0.0.2
func NewHandle[I, O any](client *HTTPClient, operation OperationReference[I, O], operationID string) (*OperationHandle[O], error)
NewHandle is the type safe version of HTTPClient.NewHandle. The [Handle.GetResult] method will return an output of type O.
func (*OperationHandle[T]) Cancel ¶
func (h *OperationHandle[T]) Cancel(ctx context.Context, options CancelOperationOptions) error
Cancel requests to cancel an asynchronous operation.
Cancelation is asynchronous and may be not be respected by the operation's implementation.
func (*OperationHandle[T]) GetInfo ¶
func (h *OperationHandle[T]) GetInfo(ctx context.Context, options GetOperationInfoOptions) (*OperationInfo, error)
GetInfo gets operation information, issuing a network request to the service handler.
func (*OperationHandle[T]) GetResult ¶
func (h *OperationHandle[T]) GetResult(ctx context.Context, options GetOperationResultOptions) (T, error)
GetResult gets the result of an operation, issuing a network request to the service handler.
By default, GetResult returns (nil, ErrOperationStillRunning) immediately after issuing a call if the operation has not yet completed.
Callers may set GetOperationResultOptions.Wait to a value greater than 0 to alter this behavior, causing the client to long poll for the result issuing one or more requests until the provided wait period exceeds, in which case (nil, ErrOperationStillRunning) is returned.
The wait time is capped to the deadline of the provided context. Make sure to handle both context deadline errors and ErrOperationStillRunning.
Note that the wait period is enforced by the server and may not be respected if the server is misbehaving. Set the context deadline to the max allowed wait period to ensure this call returns in a timely fashion.
⚠️ If a LazyValue is returned (as indicated by T), it must be consumed to free up the underlying connection.
type OperationInfo ¶
type OperationInfo struct { // ID of the operation. ID string `json:"id"` // State of the operation. State OperationState `json:"state"` }
OperationInfo conveys information about an operation.
type OperationReference ¶ added in v0.0.2
type OperationReference[I, O any] interface { Name() string // InputType the generic input type I for this operation. InputType() reflect.Type // OutputType the generic out type O for this operation. OutputType() reflect.Type // contains filtered or unexported methods }
OperationReference provides a typed interface for invoking operations. Every Operation is also an OperationReference. Callers may create references using NewOperationReference when the implementation is not available.
func NewOperationReference ¶ added in v0.0.2
func NewOperationReference[I, O any](name string) OperationReference[I, O]
NewOperationReference creates an OperationReference with the provided type parameters and name. It provides typed interface for invoking operations when the implementation is not available to the caller.
type OperationState ¶
type OperationState string
OperationState represents the variable states of an operation.
const ( // "running" operation state. Indicates an operation is started and not yet completed. OperationStateRunning OperationState = "running" // "succeeded" operation state. Indicates an operation completed successfully. OperationStateSucceeded OperationState = "succeeded" // "failed" operation state. Indicates an operation completed as failed. OperationStateFailed OperationState = "failed" // "canceled" operation state. Indicates an operation completed as canceled. OperationStateCanceled OperationState = "canceled" )
type Reader ¶ added in v0.0.2
type Reader struct { // ReaderCloser contains request or response data. May be nil for empty data. io.ReadCloser // Header that should include information on how to deserialize this content. // Headers constructed by the framework always have lower case keys. // User provided keys are considered case-insensitive by the framework. Header Header }
A Reader is a container for a Header and an io.Reader. It is used to stream inputs and outputs in the various client and server APIs.
type RegisterableOperation ¶ added in v0.0.2
type RegisterableOperation interface { // Name of the operation. Used for invocation and registration. Name() string // contains filtered or unexported methods }
A RegisterableOperation is accepted in [OperationRegistry.Register]. Embed UnimplementedOperation to implement it.
type Serializer ¶ added in v0.0.2
type Serializer interface { // Serialize encodes a value into a [Content]. Serialize(any) (*Content, error) // Deserialize decodes a [Content] into a given reference. Deserialize(*Content, any) error }
Serializer is used by the framework to serialize/deserialize input and output. To customize serialization logic, implement this interface and provide your implementation to framework methods such as NewHTTPClient and NewHTTPHandler. By default, the SDK supports serialization of JSONables, byte slices, and nils.
func DefaultSerializer ¶ added in v0.1.0
func DefaultSerializer() Serializer
DefaultSerializer returns the SDK's default Serializer that handles serialization to and from JSONables, byte slices, and nil.
type Service ¶ added in v0.0.8
type Service struct { Name string // contains filtered or unexported fields }
A Service is a container for a group of operations.
func NewService ¶ added in v0.0.8
NewService constructs a Service.
func (*Service) Operation ¶ added in v0.0.11
func (s *Service) Operation(name string) RegisterableOperation
Operation returns an operation by name or nil if not found.
func (*Service) Register ¶ added in v0.0.8
func (s *Service) Register(operations ...RegisterableOperation) error
Register one or more operations. Returns an error if duplicate operations were registered with the same name or when trying to register an operation with no name.
Can be called multiple times and is not thread safe.
type ServiceRegistry ¶ added in v0.0.8
type ServiceRegistry struct {
// contains filtered or unexported fields
}
A ServiceRegistry registers services and constructs a Handler that dispatches operations requests to those services.
func NewServiceRegistry ¶ added in v0.0.8
func NewServiceRegistry() *ServiceRegistry
func (*ServiceRegistry) NewHandler ¶ added in v0.0.8
func (r *ServiceRegistry) NewHandler() (Handler, error)
NewHandler creates a Handler that dispatches requests to registered operations based on their name.
func (*ServiceRegistry) Register ¶ added in v0.0.8
func (r *ServiceRegistry) Register(services ...*Service) error
Register one or more service. Returns an error if duplicate operations were registered with the same name or when trying to register a service with no name.
Can be called multiple times and is not thread safe.
type StartOperationOptions ¶
type StartOperationOptions struct { // Header contains the request header fields either received by the server or to be sent by the client. // // Header will always be non empty in server methods and can be optionally set in the client API. // // Header values set here will overwrite any SDK-provided values for the same key. // // Header keys with the "content-" prefix are reserved for [Serializer] headers and should not be set in the // client API; they are not available to server [Handler] and [Operation] implementations. Header Header // Callbacks are used to deliver completion of async operations. // This value may optionally be set by the client and should be called by a handler upon completion if the started operation is async. // // Implement a [CompletionHandler] and expose it as an HTTP handler to handle async completions. CallbackURL string // Optional header fields set by a client that are required to be attached to the callback request when an // asynchronous operation completes. CallbackHeader Header // Request ID that may be used by the server handler to dedupe a start request. // By default a v4 UUID will be generated by the client. RequestID string // Links contain arbitrary caller information. Handlers may use these links as // metadata on resources associated with and operation. Links []Link }
StartOperationOptions are options for the StartOperation client and server APIs.
type UnexpectedResponseError ¶
type UnexpectedResponseError struct { // Error message. Message string // Optional failure that may have been emedded in the response. Failure *Failure // Additional transport specific details. // For HTTP, this would include the HTTP response. The response body will have already been read into memory and // does not need to be closed. Details any }
Error that indicates a client encountered something unexpected in the server's response.
func (*UnexpectedResponseError) Error ¶
func (e *UnexpectedResponseError) Error() string
Error implements the error interface.
type UnimplementedHandler ¶
type UnimplementedHandler struct{}
UnimplementedHandler must be embedded into any Handler implementation for future compatibility. It implements all methods on the Handler interface, returning unimplemented errors if they are not implemented by the embedding type.
func (UnimplementedHandler) CancelOperation ¶
func (h UnimplementedHandler) CancelOperation(ctx context.Context, service, operation, operationID string, options CancelOperationOptions) error
CancelOperation implements the Handler interface.
func (UnimplementedHandler) GetOperationInfo ¶
func (h UnimplementedHandler) GetOperationInfo(ctx context.Context, service, operation, operationID string, options GetOperationInfoOptions) (*OperationInfo, error)
GetOperationInfo implements the Handler interface.
func (UnimplementedHandler) GetOperationResult ¶
func (h UnimplementedHandler) GetOperationResult(ctx context.Context, service, operation, operationID string, options GetOperationResultOptions) (any, error)
GetOperationResult implements the Handler interface.
func (UnimplementedHandler) StartOperation ¶
func (h UnimplementedHandler) StartOperation(ctx context.Context, service, operation string, input *LazyValue, options StartOperationOptions) (HandlerStartOperationResult[any], error)
StartOperation implements the Handler interface.
type UnimplementedOperation ¶ added in v0.0.2
type UnimplementedOperation[I, O any] struct{}
UnimplementedOperation must be embedded into any Operation implementation for future compatibility. It implements all methods on the Operation interface except for `Name`, returning unimplemented errors if they are not implemented by the embedding type.
func (*UnimplementedOperation[I, O]) Cancel ¶ added in v0.0.2
func (*UnimplementedOperation[I, O]) Cancel(context.Context, string, CancelOperationOptions) error
Cancel implements Operation.
func (*UnimplementedOperation[I, O]) GetInfo ¶ added in v0.0.2
func (*UnimplementedOperation[I, O]) GetInfo(context.Context, string, GetOperationInfoOptions) (*OperationInfo, error)
GetInfo implements Operation.
func (*UnimplementedOperation[I, O]) GetResult ¶ added in v0.0.2
func (*UnimplementedOperation[I, O]) GetResult(context.Context, string, GetOperationResultOptions) (O, error)
GetResult implements Operation.
func (*UnimplementedOperation[I, O]) InputType ¶ added in v0.0.11
func (*UnimplementedOperation[I, O]) InputType() reflect.Type
func (*UnimplementedOperation[I, O]) OutputType ¶ added in v0.0.11
func (*UnimplementedOperation[I, O]) OutputType() reflect.Type
func (*UnimplementedOperation[I, O]) Start ¶ added in v0.0.2
func (h *UnimplementedOperation[I, O]) Start(ctx context.Context, input I, options StartOperationOptions) (HandlerStartOperationResult[O], error)
Start implements Operation.
type UnsuccessfulOperationError ¶
type UnsuccessfulOperationError struct { // State of the operation. Only [OperationStateFailed] and [OperationStateCanceled] are valid. State OperationState // The underlying cause for this error. Cause error }
UnsuccessfulOperationError represents "failed" and "canceled" operation results.
func NewCanceledOperationError ¶ added in v0.1.0
func NewCanceledOperationError(err error) *UnsuccessfulOperationError
NewFailedOperationError is shorthand for constructing an UnsuccessfulOperationError with State set to OperationStateCanceled and the given err as the Cause.
func NewFailedOperationError ¶ added in v0.1.0
func NewFailedOperationError(err error) *UnsuccessfulOperationError
NewFailedOperationError is shorthand for constructing an UnsuccessfulOperationError with State set to OperationStateFailed and the given err as the Cause.
func (*UnsuccessfulOperationError) Error ¶
func (e *UnsuccessfulOperationError) Error() string
Error implements the error interface.
func (*UnsuccessfulOperationError) Unwrap ¶ added in v0.1.0
func (e *UnsuccessfulOperationError) Unwrap() error
Unwrap returns the cause for use with utilities in the errors package.