nexus

package
v0.0.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 21, 2024 License: MIT Imports: 19 Imported by: 1

Documentation

Overview

Package nexus provides client and server implementations of the Nexus HTTP API

Index

Examples

Constants

View Source
const (
	StatusDownstreamError   = 520
	StatusDownstreamTimeout = 521
)

Variables

View Source
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 *Client, operation OperationReference[I, O], input I, request ExecuteOperationOptions) (O, error)

ExecuteOperation is the type safe version of Client.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 Header
}

CancelOperationOptions are options for the CancelOperation client and server APIs.

type Client

type Client struct {
	// contains filtered or unexported fields
}

A Client 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 Client.NewHandle for existing operations.

func NewClient

func NewClient(options ClientOptions) (*Client, error)

NewClient creates a new Client from provided ClientOptions. Only BaseServiceURL is required.

func (*Client) ExecuteOperation

func (c *Client) 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.Client

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 (*Client) NewHandle

func (c *Client) 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 (*Client) StartOperation

func (c *Client) 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:

  1. 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.

  2. 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.

  3. The operation was unsuccessful. The returned result will be nil and error will be an UnsuccessfulOperationError.

  4. 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.Client

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.Failure.Message)
		}
		// handle error here
	}
	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 ClientOptions

type ClientOptions struct {
	// Base URL of the service.
	ServiceBaseURL 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
}

ClientOptions are options for creating a Client.

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]
}

ClientStartOperationResult is the return type of Client.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 *Client, operation OperationReference[I, O], input I, request StartOperationOptions) (*ClientStartOperationResult[O], error)

StartOperation is the type safe version of Client.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
}

CompletionHandlerOptions are options for NewCompletionHTTPHandler.

type CompletionRequest

type CompletionRequest struct {
	// The original HTTP request.
	HTTPRequest *http.Request
	// State of the operation.
	State OperationState
	// Parsed from request and set if State is failed or canceled.
	Failure *Failure
	// 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
	// Header to attach to start and get-result requests. Optional.
	//
	// Header keys with the "content-" prefix are reserved for [Serializer] headers and should not be set in the
	// client API; they are not be avaliable 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 Client.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.

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 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 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 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, 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, operation, operationID string, options GetOperationResultOptions) (any, error)
	// GetOperationInfo handles requests to get information about an asynchronous operation.
	GetOperationInfo(ctx context.Context, 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, 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, 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, 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.UnsuccessfulOperationError{State: nexus.OperationStateFailed, Failure: nexus.Failure{Message: err.Error()}}
		}
		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.UnsuccessfulOperationError{State: nexus.OperationStateFailed, Failure: nexus.Failure{Message: err.Error()}}
		}
		return result, nil
	}
}

func (h *myHandler) CancelOperation(ctx context.Context, operation, operationID string, options nexus.CancelOperationOptions) error {
	// Handlers must implement this.
	panic("unimplemented")
}

func (h *myHandler) GetOperationInfo(ctx context.Context, 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(ctx context.Context, header nexus.Header) error {
	// Authorization for demo purposes
	if header.Get("Authorization") != "Bearer top-secret" {
		return &nexus.HandlerError{Type: nexus.HandlerErrorTypeUnauthorized, Failure: &nexus.Failure{Message: "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 {
	// Defaults to HandlerErrorTypeInternal
	Type HandlerErrorType
	// Failure to report back in the response. Optional.
	Failure *Failure
}

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 and a formatted failure message.

func (*HandlerError) Error

func (e *HandlerError) Error() string

Error implements the error interface.

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"
	// The caller does not have permission to execute the specified operation.
	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"
	// The service is currently unavailable.
	HandlerErrorTypeUnavailable HandlerErrorType = "UNAVAILABLE"
	// Used by gateways to report that a downstream server has responded with an error.
	HandlerErrorTypeDownstreamError HandlerErrorType = "DOWNSTREAM_ERROR"
	// Used by gateways to report that a request to a downstream server has timed out.
	HandlerErrorTypeDownstreamTimeout HandlerErrorType = "DOWNSTREAM_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
}

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

type HandlerStartOperationResultAsync struct {
	OperationID string
}

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 map[string]string

Header is a mapping of string to string. It is used throughout the framework to transmit metadata.

func (Header) Get added in v0.0.2

func (h Header) Get(k string) string

Get is a case-insensitive key lookup from the header map.

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 (*LazyValue) Consume added in v0.0.2

func (l *LazyValue) Consume(v any) error

Consume consumes the lazy value, decodes it from the underlying Reader, and stores the result in the value pointed to by v.

var v int
err := lazyValue.Consume(&v)

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 OperationCompletionSuccesfulOptions added in v0.0.6

type OperationCompletionSuccesfulOptions struct {
	// Optional serializer for the result. Defaults to the SDK's default Serializer, which handles JSONables, byte
	// slices and nils.
	Serializer Serializer
}

OperationCompletionSuccesfulOptions are options for NewOperationCompletionSuccessful.

type OperationCompletionSuccessful

type OperationCompletionSuccessful struct {
	// Header to send in the completion request.
	Header http.Header
	// Body to send in the completion HTTP request.
	// If it implements `io.Closer` it will automatically be closed by the client.
	Body io.Reader
}

OperationCompletionSuccessful is input for NewCompletionHTTPRequest, used to deliver successful operation results.

func NewOperationCompletionSuccessful

func NewOperationCompletionSuccessful(result any, options OperationCompletionSuccesfulOptions) (*OperationCompletionSuccessful, error)

NewOperationCompletionSuccessful constructs an OperationCompletionSuccessful from a given result.

type OperationCompletionUnsuccessful

type OperationCompletionUnsuccessful struct {
	// Header to send in the completion request.
	Header http.Header
	// State of the operation, should be failed or canceled.
	State OperationState
	// Failure object to send with the completion.
	Failure *Failure
}

OperationCompletionUnsuccessful is input for NewCompletionHTTPRequest, used to deliver unsuccessful operation results.

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 *Client, operation OperationReference[I, O], operationID string) (*OperationHandle[O], error)

NewHandle is the type safe version of Client.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

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
	// 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 OperationRegistry added in v0.0.2

type OperationRegistry struct {
	// contains filtered or unexported fields
}

An OperationRegistry registers operations and constructs a Handler that dispatches requests to those operations.

func (OperationRegistry) NewHandler added in v0.0.2

func (r OperationRegistry) NewHandler() (Handler, error)

NewHandler creates a Handler that dispatches requests to registered operations based on their name.

func (*OperationRegistry) Register added in v0.0.2

func (r *OperationRegistry) Register(operations ...RegisterableOperation) error

Register one or more operations. Returns an error if duplicate operations were registered with the same name.

Can be called multiple times and is not thread safe.

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 NewClient and NewHTTPHandler. By default, the SDK supports serialization of JSONables, byte slices, and nils.

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 keys with the "content-" prefix are reserved for [Serializer] headers and should not be set in the
	// client API; they are not be avaliable 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
}

StartOperationOptions are options for the StartOperation client and server APIs.

type UnexpectedResponseError

type UnexpectedResponseError struct {
	// Error message.
	Message string
	// The HTTP response. The response body will have already been read into memory and does not need to be closed.
	Response *http.Response
	// Optional failure that may have been emedded in the HTTP response body.
	Failure *Failure
}

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, operation, operationID string, options CancelOperationOptions) error

CancelOperation implements the Handler interface.

func (UnimplementedHandler) GetOperationInfo

func (h UnimplementedHandler) GetOperationInfo(ctx context.Context, operation, operationID string, options GetOperationInfoOptions) (*OperationInfo, error)

GetOperationInfo implements the Handler interface.

func (UnimplementedHandler) GetOperationResult

func (h UnimplementedHandler) GetOperationResult(ctx context.Context, operation, operationID string, options GetOperationResultOptions) (any, error)

GetOperationResult implements the Handler interface.

func (UnimplementedHandler) StartOperation

func (h UnimplementedHandler) StartOperation(ctx context.Context, 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

Cancel implements Operation.

func (*UnimplementedOperation[I, O]) GetInfo added in v0.0.2

GetInfo implements Operation.

func (*UnimplementedOperation[I, O]) GetResult added in v0.0.2

GetResult implements Operation.

func (*UnimplementedOperation[I, O]) Start added in v0.0.2

Start implements Operation.

type UnsuccessfulOperationError

type UnsuccessfulOperationError struct {
	State   OperationState
	Failure Failure
}

UnsuccessfulOperationError represents "failed" and "canceled" operation results.

func (*UnsuccessfulOperationError) Error

Error implements the error interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL