Documentation
¶
Index ¶
- Constants
- type ContentFileNameGetter
- type ContentFileNameSetter
- type ContentGetter
- type ContentLengthGetter
- type ContentLengthSetter
- type ContentRangeGetter
- type ContentRangeSetter
- type ContentSetter
- type ContentTypeGetter
- type ContentTypeSetter
- type Endpoint
- type EndpointRoute
- type Gateway
- type GatewayMiddleware
- type GatewayType
- type HandlerFunc
- type MiddlewareFunc
- type MiddlewareFuncs
- type OnPanicFunc
- type Redirector
- type RedirectorPermanent
- type Server
- type ServerOption
- type Service
- type StreamRequest
- type StreamResponse
- func (res *StreamResponse) Content() io.ReadCloser
- func (res *StreamResponse) ContentFileName() string
- func (res *StreamResponse) ContentLength() int
- func (res *StreamResponse) ContentRange() (start int, end int, size int)
- func (res *StreamResponse) ContentType() string
- func (res *StreamResponse) SetContent(content io.ReadCloser)
- func (res *StreamResponse) SetContentFileName(contentFileName string)
- func (res *StreamResponse) SetContentLength(contentLength int)
- func (res *StreamResponse) SetContentRange(start int, end int, size int)
- func (res *StreamResponse) SetContentType(contentType string)
- type StructPointer
Constants ¶
const ( // GatewayTypeAPI marks a gateway as being an HTTP/RPC API gateway. GatewayTypeAPI = GatewayType("API") // GatewayTypeEvents marks a gateway as being event-sourced using publish/subscribe. GatewayTypeEvents = GatewayType("EVENTS") )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ContentFileNameGetter ¶
type ContentFileNameGetter interface { // ContentFileName returns the name of the file that should be used when downloading this stream. ContentFileName() string }
ContentFileNameGetter is used to supply an optional Content-Disposition header, allowing you to customize the name of the file presented in download modals of browsers/clients.
type ContentFileNameSetter ¶
type ContentFileNameSetter interface { // SetContentFileName applies the name of the file that should be used when downloading this stream. SetContentFileName(string) }
ContentFileNameSetter is used to supply an optional Content-Disposition header, allowing you to customize the name of the file presented in download modals of browsers/clients.
type ContentGetter ¶
type ContentGetter interface { // Content returns the stream of exact bytes to send back to the caller. Content() io.ReadCloser }
ContentGetter provides a way for your service response to indicate that you want to return a raw stream of bytes rather than relying on our auto-encoding.
type ContentLengthGetter ¶
type ContentLengthGetter interface { // ContentLength returns the total number of bytes you can/should read from the Content stream. ContentLength() int }
ContentLengthGetter is used by raw response streams to indicate exactly how many bytes are in the response's Content stream.
type ContentLengthSetter ¶
type ContentLengthSetter interface { // SetContentLength applies the total number of bytes you can/should read from the Content stream. SetContentLength(int) }
ContentLengthSetter recaptures the custom content length header from raw responses when using the code-generate Go client for your services.
type ContentRangeGetter ¶
type ContentRangeGetter interface { // ContentRange returns the individual values used to build a custom Content-Range header // when responding with a raw content stream. For more information on how these values are // used, please see: https://www.geeksforgeeks.org/http-headers-content-range/ ContentRange() (start int, end int, size int) }
ContentRangeGetter is used by raw response streams to indicate that this is resumable using the standard Range header.
type ContentRangeSetter ¶
type ContentRangeSetter interface { // SetContentRange accepts the 3 standard components of the Content-Range header. SetContentRange(start int, end int, size int) }
ContentRangeSetter recaptures the custom content range header from raw responses when using the code-generated Go client for your services.
type ContentSetter ¶
type ContentSetter interface { // SetContent applies the stream of bytes that the response object should use when reading. SetContent(io.ReadCloser) }
ContentSetter allows raw stream responses to be properly reconstituted when using the code-generated Go client for your service.
type ContentTypeGetter ¶
type ContentTypeGetter interface { // ContentType returns the MIME encoding type of the raw content stream. ContentType() string }
ContentTypeGetter is used by raw response streams to indicate what type of data is in the stream.
type ContentTypeSetter ¶
type ContentTypeSetter interface { // SetContentType sets the MIME encoding type of the raw content stream. SetContentType(string) }
ContentTypeSetter recaptures the custom content type header from raw responses when using the code-generated Go client for your service.
type Endpoint ¶
type Endpoint struct { // ServiceName is the name of the service that this operation is part of. ServiceName string // Name is the name of the function/operation that this endpoint describes. Name string // Handler is the actual function that will trigger the work on then underlying // service to accomplish the work that this endpoint is intended to. Handler HandlerFunc // NewInput returns a pointer to the struct that we pass into the handler function // for this input (e.g. "*LoginRequest"). It is the request struct pointer. NewInput func() StructPointer // Roles helps support role-based security by defining role patterns to indicate which // users are allowed to access this endpoint. For example: // // endpoint.Roles = []string{ // "admin.write", // "group.{Group.ID}.write", // } // // Notices that the roles should be allowed to have path variables that we can fill in // at runtime with the incoming binding data. Roles []string // Routes defines the actual ingress routes that allow this service operation to // be invoked by various gateways. For instance, they tell you that you can invoke // the API call "GET /user/{ID}" to invoke it or that it should trigger when the // event "ON UserService.UserCreated" fires. Routes []EndpointRoute }
Endpoint describes an operation on an underlying service that we expose through one of potentially multiple gateways. The Routes on this Endpoint indicate all of the ingress mechanisms available to invoke this operation.
func (Endpoint) QualifiedName ¶
QualifiedName returns the fully-qualified name/identifier of this service operation. It is simply the formatted string "ServiceName.MethodName".
type EndpointRoute ¶
type EndpointRoute struct { // GatewayType indicates the type of gateway that should service this route. For instance // if the type is "HTTP" then the API gateway should take care of it. If the type // is "EVENT" then we should let our pub-sub event source take care of it. GatewayType GatewayType // Method describes some sort of action/verb that describes this route. For API endpoints // it is the HTTP method (e.g. GET, PUT, POST, etc). For events it is "ON", and so forth. Method string // Path describes the actual unique routing path that the gateway should use to ensure // that requests get to this endpoint. For API endpoints, it's the request path // like "/user/{ID}" and for event endpoints, it's the subscription key like "FooService.Save". Path string // PathParams contains the names of the path variables/parameters you expect in the path of // this endpoint. For instance, the path "/user/{UserID}/transaction/{TransactionID}" would set // this slice to []string{"UserID", "TransactionID"}. This allows you to quickly bind only the // values you expect in the pattern. PathParams []string // Status is mainly used by API gateway routes to determine what HTTP status code we should // return to the caller when this endpoint succeeds. By default, this is 200. Status int }
EndpointRoute defines an actual ingress route that allows a service operation to be invoked by various gateways. For instance, one route will tell you that you can invoke the API call "GET /user/{ID}" to invoke the method or that it should run when the event "ON UserService.UserCreated" fires.
type Gateway ¶
type Gateway interface { // Type returns the identifier used to distinguish this gateway from others registered // for the same service. Type() GatewayType // Register adds an ingress handler for the given operation/endpoint to this gateway. Register(endpoint Endpoint, route EndpointRoute) // Listen causes the gateway to start accepting requests to invoke methods on the // underlying service. Implementations should attempt to follow these rules: // // * Block on the current Goroutine. This should unblock on an abnormal interruption // to the gateway's ability to continue processing or if Shutdown() has been // called elsewhere. // * The error should be 'nil' if nothing has gone wrong. This is different from the // behavior of http.ListenAndServe() which returns a http.ErrServerClosed error // even when things shut down as expected. Gateway instances should keep their // whore mouths shut and only report an error when there's actually something // to be concerned about. Listen() error // Shutdown should attempt to gracefully wind down processing of requests. Where // possible, you should use the context to determine if/when you should give up // on dealing with existing work. Implementations should try to follow these rules: // // * Immediately stop accepting incoming requests. // * Allow in-process requests to finish cleanly. // * Abide any cancellation of the context and give up on existing requests. Shutdown(ctx context.Context) error }
Gateway describes a way to execute operations on some underlying service. By default, service methods are closed off to all external processes, but gateways provide a protocol such as HTTP/RPC or PubSub to trigger them. How that actually happens is completely up to the Gateway implementation - the interface merely provides signals to start/stop the mechanism that accepts/processes function calls.
type GatewayMiddleware ¶
type GatewayMiddleware interface { Gateway // Middleware are the functions that a Server should add to EVERY endpoint it registers. Middleware() MiddlewareFuncs }
GatewayMiddleware allows gateway implementations to add special middleware to the standard execution pipeline for an endpoint. Your gateway would implement this when it has special functionality you want included in the execution of every endpoint regardless of which gateway is actually servicing it.
The canonical example for this is the event gateway. When a service method gets invoked, we want to publish a "Service.Method" event afterwards no matter what so that the rest of your system can be notified about the event. We don't care if it was an HTTP request that triggered the invocation or some other event handler. We just know that we want to publish an event no matter what. The event middleware can return a handler(s) that injects that behavior by hiding it behind a generic middleware function.
type GatewayType ¶
type GatewayType string
GatewayType is a tagging value that gateways can use to classify themselves.
func (GatewayType) String ¶
func (t GatewayType) String() string
String returns the raw string value for the type.
type HandlerFunc ¶
HandlerFunc is the general purpose signature for any endpoint handler.
type MiddlewareFunc ¶
MiddlewareFunc is a function that can be used to decorate a service method/endpoint's handler.
type MiddlewareFuncs ¶
type MiddlewareFuncs []MiddlewareFunc
MiddlewareFuncs is an ordered pipeline of operations that must occur before invoking a service method/endpoint's handler.
func (MiddlewareFuncs) Append ¶
func (funcs MiddlewareFuncs) Append(mw ...MiddlewareFunc) MiddlewareFuncs
Append creates a new middleware function pipeline that runs the original handlers and then the additional ones specified by 'mw'.
func (MiddlewareFuncs) Then ¶
func (funcs MiddlewareFuncs) Then(handler HandlerFunc) HandlerFunc
Then creates a single handler function that executes every operation in the middleware pipeline and terminates with the supplied handler.
type OnPanicFunc ¶
OnPanicFunc is the signature for custom callbacks to invoke when a panic occurs in your service code.
type Redirector ¶
type Redirector interface { // Redirect returns the URI of an alternate resource that will provide the final data // we want this endpoint to return. Redirect() string }
Redirector provides a way to tell gateways that the response value doesn't contain the raw byte stream we want to deliver. Instead, you should redirect to that URI to fetch the response data.
This indicates the redirect is temporary, and you should probably continue to use the same endpoint address in the future. You'd probably use this more in cases such as redirecting to a file on S3; something that will be different each time.
GATEWAY COMPATABILITY: This currently only works with the API gateway. When delivering/receiving responses through other gateways such as "Events", your response will be auto-encoded just like it was a normal struct/value. As a result, your response should continue to maintain exported fields that you would like to transport in those cases.
type RedirectorPermanent ¶
type RedirectorPermanent interface { // RedirectPermanent returns the URI of an alternate resource that will provide the final data // we want this endpoint to return. RedirectPermanent() string }
RedirectorPermanent provides a way to tell gateways that the response value doesn't contain the raw byte stream we want to deliver. Instead, you should redirect to that URI to fetch the response data.
This indicates that the redirect is permanent, and you should probably start using the redirected URI moving forward. You'd probably use this more in a situation where you are deprecating one API endpoint in favor of another. The old endpoint could redirect to the new endpoint to maintain backwards compatability, but you really should start using the new one.
GATEWAY COMPATABILITY: This currently only works with the API gateway. When delivering/receiving responses through other gateways such as "Events", your response will be auto-encoded just like it was a normal struct/value. As a result, your response should continue to maintain exported fields that you would like to transport in those cases.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the primordial component that wrangles all of your services and gateways to get them talking to each other. You should not create one of these yourself. Instead, you should use the NewServer() constructor to do that for you.
func NewServer ¶
func NewServer(options ...ServerOption) *Server
NewServer creates a new container that encapsulates one or more gateways and services. It helps set up endpoint routes and manages startup/shutdown routines so that you can start/stop accepting service requests.
Example:
calcHandler := calc.CalculatorServiceHandler{} calcServer := gen.NewCalculatorService(calcHandler) server := services.NewServer( services.Listen(apis.NewGateway()), services.Listen(events.NewGateway()), services.Register(calcServer), )
func (*Server) Invoke ¶
func (server *Server) Invoke(ctx context.Context, serviceName string, methodName string, req any) (any, error)
Invoke allows you to manually trigger any registered service endpoint/function given the name of the service/method. I'd suggest you stick to using the generated clients to invoke functions on your services rather than using this. This primarily exists to aid in testing - it's not really mean to be used in production code. But hey, you're an adult. Do what you want.
func (*Server) Run ¶
Run turns on every gateway currently assigned to this service runtime. Call this once your service setup and registration is complete in order to start accepting incoming requests through your gateway(s).
func (*Server) Shutdown ¶
Shutdown attempts to gracefully shut down all of the gateways associated with this service runtime. It should immediately stop accepting new requests and then wait for existing requests to finish before returning. The context should be used to provide a cancellation/timeout to limit how long this will wait for in-flight requests to finish up.
func (*Server) ShutdownOnInterrupt ¶
ShutdownOnInterrupt provides some convenience around shutting down this service. This function will block until the process either receives a SIGTERM or SIGINT signal. At that point, it will invoke Shutdown() whose context will have a deadline of the given duration.
Example:
// Ignore the bad (non-existent) error handling, but here's how your server // setup/teardown code looks using ShutdownOnInterrupt. The server will start // up and run until the process gets a SIGINT/SIGTERM signal. At that point, it // will give all in-process requests in all gateways 10 seconds to finish. void main() { server := services.NewServer(...) go server.ShutdownOnInterrupt(10*time.Second) server.Run() }
type ServerOption ¶
type ServerOption func(*Server)
ServerOption defines a setting that you can change on a services.Server while setting up your application in main().
func Listen ¶
func Listen(gw Gateway) ServerOption
Listen adds another gateway to the server. You can supply this option more than once in order to provide multiple types of gateways. For instance, you can call it once to provide settings for an API/HTTP gateway and again to provide settings for an event source gateway.
func OnPanic ¶
func OnPanic(handler OnPanicFunc) ServerOption
OnPanic provides a custom callback that will let you log/observe the error/stack from any panic that occurred in your service method code.
func Register ¶
func Register(services ...*Service) ServerOption
Register adds endpoint handlers for the given service(s) to the appropriate gateways. Typically, you don't create the Service pointer yourself. These are built for you when you use the code generation tools to build the gateways based on your service interfaces.
Consider this call akin to adding routes to an HTTP router. This just adds routes to every applicable gateway in your runtime server.
type Service ¶
type Service struct { // Name is the name of the service interface that we're building a server for. Name string // Version is an optional version identifier for this service. Version string // Handler is a reference to the actual service handler struct you provided during // setup of the gateway runtime in main. Handler any // Endpoints contains registration/execution information for every method/operation // that the service exposes. Endpoints []Endpoint }
Service encapsulates your hand-implemented service handler and includes all of the endpoint registration information required to power our runtime gateways.
type StreamRequest ¶
type StreamRequest struct {
// contains filtered or unexported fields
}
StreamRequest implements all of the ContentXxx and SetContentXxx methods that we support and look at when we look at streaming/upload style requests.
type FileUploadRequest struct { services.StreamRequest } func (res *ImageDownloadResponse) Init(file os.File, info fs.FileInfo) { res.SetContent(file) res.SetContentType("image/png") res.SetContentLength(info.Size()) }
type StreamResponse ¶
type StreamResponse struct {
// contains filtered or unexported fields
}
StreamResponse implements all of the ContentXxx and SetContentXxx methods that we support. You can embed one of these structs in your response struct to automatically gain the ability to respond with raw data streams rather than auto-encoding.
type ImageDownloadResponse struct { services.StreamResponse } func (res *ImageDownloadResponse) Init(file os.File, info fs.FileInfo) { res.SetContent(file) res.SetContentType("image/png") res.SetContentLength(info.Size()) }
func (*StreamResponse) Content ¶
func (res *StreamResponse) Content() io.ReadCloser
Content returns the raw byte stream representing the data returned by the endpoint.
func (*StreamResponse) ContentFileName ¶
func (res *StreamResponse) ContentFileName() string
ContentFileName returns the name of the file the client should use to download the stream.
func (*StreamResponse) ContentLength ¶
func (res *StreamResponse) ContentLength() int
ContentLength returns the number of bytes you can read from the content stream.
func (*StreamResponse) ContentRange ¶
func (res *StreamResponse) ContentRange() (start int, end int, size int)
ContentRange returns non-zero values if this resource supports the ability to resume downloads.
func (*StreamResponse) ContentType ¶
func (res *StreamResponse) ContentType() string
ContentType returns the MIME content type string describe the type of data in the stream.
func (*StreamResponse) SetContent ¶
func (res *StreamResponse) SetContent(content io.ReadCloser)
SetContent applies the raw byte stream representing the data returned by the endpoint.
func (*StreamResponse) SetContentFileName ¶
func (res *StreamResponse) SetContentFileName(contentFileName string)
SetContentFileName sets the name of the file the client should use to download the stream.
func (*StreamResponse) SetContentLength ¶
func (res *StreamResponse) SetContentLength(contentLength int)
SetContentLength sets the number of bytes the caller should read from the content stream.
func (*StreamResponse) SetContentRange ¶
func (res *StreamResponse) SetContentRange(start int, end int, size int)
SetContentRange applies the attributes related to controlling resumable downloads.
func (*StreamResponse) SetContentType ¶
func (res *StreamResponse) SetContentType(contentType string)
SetContentType applies the MIME content type that describes the data in the stream.
type StructPointer ¶
type StructPointer any
StructPointer is a tagging type used to indicate either a pointer to the "request" struct to service methods or a pointer to the "response" struct of the method.