Overview
The Restate Go SDK is open source and can be found on GitHub: (sdk-go repo).
Have a look at the Go Quickstart!
Add the github.com/restatedev/sdk-go
dependency to your project to start developing Restate services.
The Restate SDK lets you implement handlers. Handlers can either be part of a Service, or a Virtual Object. Let's have a look at how to define them.
Services
Services and their handlers are defined as follows:
package mainimport ("context""fmt""log"restate "github.com/restatedev/sdk-go"server "github.com/restatedev/sdk-go/server")type MyService struct{}func (MyService) MyHandler(ctx restate.Context, greeting string) (string, error) {return fmt.Sprintf("%s!", greeting), nil}func main() {if err := server.NewRestate().Bind(restate.Reflect(MyService{})).Start(context.Background(), "0.0.0.0:9080"); err != nil {log.Fatal(err)}}
- Define a Service by implementing exported methods on any struct.
- By default, the service name is the name of the struct, so the service can be
called at
<RESTATE_INGRESS_URL>/MyService/MyHandler
. - The service definition contains a list of handlers.
Each handler is just function that implements the handler logic. The handler
will be named the same way as the method.
The function has the Restate Context as its first argument.
Within the handler, you use the
Context
to interact with Restate. The SDK stores the actions you do on the context in the Restate journal to make them durable. - The handler input parameters and return type can be of any type, as long as
they can be serialized. By default, serialization is done with
JSONCodec
which usesencoding/json
. Input types, output types, and even errors are not mandatory and can be omitted if your handler doesn't need them. - Pass the
MyService
struct torestate.Reflect
which uses reflection to turn the methods into handlers. It will skip unexported methods and those that don't have the expected signature - see the package documentation for a list of allowed signatures. - Finally, create a server listening on the specified address and bind the service(s) to it.
Virtual Objects
Virtual Objects and their handlers are defined similarly to services, with the following differences:
package mainimport ("context""fmt""log"restate "github.com/restatedev/sdk-go"server "github.com/restatedev/sdk-go/server")type MyVirtualObject struct{}func (MyVirtualObject) MyHandler(ctx restate.ObjectContext, greeting string) (string, error) {return fmt.Sprintf("%s %s!", greeting, restate.Key(ctx)), nil}func (MyVirtualObject) MyConcurrentHandler(ctx restate.ObjectSharedContext, greeting string) (string, error) {return fmt.Sprintf("%s %s!", greeting, restate.Key(ctx)), nil}func main() {if err := server.NewRestate().Bind(restate.Reflect(MyVirtualObject{})).Start(context.Background(), "0.0.0.0:9080"); err != nil {log.Fatal(err)}}
- The first argument of each handler must be the
ObjectContext
parameter. Handlers with theObjectContext
parameter can write to the K/V state store. Only one handler can be active at a time, to ensure consistency. - You can retrieve the key of the object you are in via
restate.Key(ctx)
. - If you want to have a handler that executes concurrently to the others and
doesn't have write access to the K/V state, instead use the
ObjectSharedContext
. You can use these handlers, for example, to read K/V state and expose it to the outside world, or to interact with the blocking handler (e.g. resolve awakeables).
The Go SDK also supports defining handlers and input/output types using code generation from Protocol Buffers. See Code Generation for more details.
Now that you have a high-level idea of what a Restate service might look like, let's have a look at what the Restate Context allows you to do.