abstract class ServiceFragment extends ActorService with ServiceEndpoints
A service fragment is an object defining a logical service. Service fragments must be instantiated under a group with a name to use. This scopes all endpoints, authorization, and entity data to that group and name.
An object extending this class declares a new service fragment. A service has a protocol of commands, queries and events. Operators can use the protocol directly. Users can only use the protocol through the declared endpoints.
The usability focus is on rapid development and data acquisition:
- easy declaration of the commands, queries and events
- automatic auditing
- components for common business as a service activities
A service is three declarations:
- A protocol consisting of commands and queries
- A mapping from protocol messages to implementations
- an interface exported to users as endpoints
This is implemented in this EDSL as:
- Types in the Proto hierarchy. Commands extend Command and Queries extend Query.
- Implementations defined by (partial) functions from messages in this protocol to a handler. Handlers can delegate to akka actors, event source entities, ZIO actions, or plain functions.
- the exports of commands and queries are REST endpoints. These consist of explicit (verb, path components, data) and implicit (auth token, session token, csrf token, origin) data plus a mapping to the Proto.
Scopes If services.IntegerCounters was instantiated under a group
doors
with the service nameentrances
andexits
then these would not share data. The entity/doors/entrances/front
would have a different state than/doors/exits/front
. Even though the object,IntegerCounters
, is the same. , Minimal service fragment definition
import glngn.prelude._ object MinimalServiceFragment extends ServiceFragment { sealed trait Proto extends Message }
, A hypothetical service fragment definition
// a hypothetical service for account balances final object ClientBalanceFragment extends ServiceFragment { type AccountId = EntityId type CurrencyValue = Int // fractions of currency unit // messages in the protocol sealed trait Proto extends Message // a command to increase the balance of an account case class IncBalanceForAccount(account: AccountId, amount: CurrencyValue) extends Command[CurrencyValue] with Proto // a command to decrease the balance of an account case class DecBalanceForAccount(account: AccountId, amount: CurrencyValue) extends Command[CurrencyValue] with Proto // a query to retrieve the account balance case class GetBalanceForAccount(account: AccountId) extends Query[CurrencyValue] with Proto // an event outside of the command/query model. case class RequestAudit(account: AccountId) extends Proto override def instantiate(env: InstanceEnv) = new Instance(env) { import Bindings.{delegate, entity, async} // the service protocol is implemented using... val bindings = bindingsChain( // ... a akka typed Behavior[Envelope] delegate delegate { Behaviors.receiveMessagePartial case Event(RequestAudit) => ??? } // Note the use of a partial function: unhandled messages will propagate to the // next binding. (Even if the delegate behavior above changes) }, // ... operations on a named counter entity entity(NamedValue) { case IncBalanceForAccount(accountId, amount) => CounterEntity.Inc(amount) -> accountId case DecBalanceForAccount(accountId, amount) => CounterEntity.Dec(amount) -> accountId case GetBalanceForAccount(accountId) => CounterEntity.Get -> accountId }, // ... a daemon sending Proto messages back to this service async(OrdersOverSMSBehavior) // where OrdersOverSMSBehavior being a [[ServiceActorDaemon]] ) import Endpoints.{query, command} // The protocol is exported to users with the endpoints def endpoints: Endpoints[_] = endpointsChain( // results in the REST interface: // // GET $accountName // POST $accountName/inc // POST $accountName/dec // // once instantiated this is schema can be viewed under /openapi.json query.entityId { accountName => GetBalanceForAccount(accountName) }, command.entityId.slug("inc").value[CurrencyValue] { (accountId, amount) => IncBalanceForAccount(accountId, amount) }, command.entityId.slug("dec").value[CurrencyValue] { (accountId, amount) => DecBalanceForAccount(accountId, amount) } ) } }
- Grouped
- Alphabetic
- By Inheritance
- ServiceFragment
- ServiceEndpoints
- ActorService
- ServiceBindings
- ServiceActor
- DirectLogging
- AnyRef
- Any
- Hide All
- Show All
- Public
- All
Instance Constructors
- new ServiceFragment(logicalIdInput: String = "")
Type Members
-
final
type
AnyRequest = Proto with Request[_]
AnyRequest is a Command or Query with no particular response type.
- Definition Classes
- ServiceActor
-
final
type
Bindings[A] = FreeApplicative[BindingsOp, A]
Type of bindings declaration.
Type of bindings declaration.
- Definition Classes
- ServiceBindings
-
final
type
Delegate = ActorRef[Envelope]
The delegate is an actor accepting events in Envelope messages.
The delegate is an actor accepting events in Envelope messages.
- Definition Classes
- ServiceBindings
-
final
type
Endpoints[A] = FreeApplicative[EndpointsOp, A]
- Definition Classes
- ServiceEndpoints
- abstract class Instance extends EndpointsInstance with ServiceInstance
- case class InstanceEnv(spawner: ActorSpawner, injector: ImpureInjector, groupId: GroupId, serviceId: ServiceId) extends BindingsInstanceEnv with Product with Serializable
-
abstract
type
Proto <: Message
The commands, queries and events all implement Proto.
The commands, queries and events all implement Proto. Easy inferrence of operations schema and endpoint schema assumes the use of a sealed trait.
- Definition Classes
- ServiceActor
a typical definition
sealed trait Proto extends Message
, an event type
AnEvent
inProto
sealed trait Proto extends Message case class AnEvent(msg: String) extends Proto
Examples: -
trait
ServiceInstance extends BindingsInstance
- Definition Classes
- ActorService
-
abstract
class
Command[Response] extends Request[Response] with proto.ProtoDecl.Command with proto.ProtoDecl.Request
All commands are Requests with Proto:
extends Command[R] with Proto
.All commands are Requests with Proto:
extends Command[R] with Proto
.sealed trait Proto extends Message case class ExampleCommand(msg: String) extends Command[ExampleResponse] with Proto
- Definition Classes
- ServiceActor
-
sealed
trait
Envelope extends Product with Message with Serializable
A Proto event with additional attributes and claims.
A Proto event with additional attributes and claims. To pattern match on an Envelope use the Event.unapply or Request.unapply extractors.
val behavior: Behavior[Envelope] = Behaviors.receiveMessagePartial { case Event(SomeEvent(eventData)) => ??? case Request(scope, SomeCommand(eventData)) => ??? }
An Envelope can be implicitly constructed from any Proto.
val delegate: ActorRef[Envelope] = ??? val anEvent: Proto = SomeEvent(eventData) delegate ! anEvent
- Definition Classes
- ServiceActor
-
abstract
class
Query[Response] extends Request[Response] with proto.ProtoDecl.Query with proto.ProtoDecl.Request
All queries are Requests with Proto:
extends Query[R] with Proto
.All queries are Requests with Proto:
extends Query[R] with Proto
.sealed trait Proto extends Message case class ExampleQuery(msg: String) extends Query[ExampleResponse] with Proto
- Definition Classes
- ServiceActor
-
sealed abstract
class
Request[R] extends AnyRef
A protocol event can be declared as a Request using Command or Query.
A protocol event can be declared as a Request using Command or Query. The type parameter is the response that resolves the request.
sealed trait Proto extends Message case class ExampleCommand(msg: String) extends Command[ExampleResponse] with Proto case class ExampleQuery(msg: String) extends Query[ExampleResponse] with Proto
- Definition Classes
- ServiceActor
-
trait
BindingsInstance extends AnyRef
- Definition Classes
- ServiceBindings
-
implicit
class
DelegateOps extends AnyRef
- Definition Classes
- ServiceBindings
-
abstract
class
EndpointsInstance extends BindingsInstance
- Definition Classes
- ServiceEndpoints
-
sealed
trait
EndpointsOp[A] extends AnyRef
- Definition Classes
- ServiceEndpoints
Abstract Value Members
-
abstract
def
instantiate(env: InstanceEnv): Instance
Instantiates this service fragment with the given environment.
Instantiates this service fragment with the given environment.
TODO: composition instead of requiring the
Instance
interface?An empty instance with no bindings or endpoints.
def instantiate(env: InstanceEnv) = Instance.empty(env)
, The empty instance is exactly
def instantiate(env: InstanceEnv) = new Instance(env) { val bindings: Bindings[_] = Bindings.empty def endpoints: Endpoints[_] = Endpoints.empty }
Examples:
Concrete Value Members
-
final
def
!=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
final
def
##(): Int
- Definition Classes
- AnyRef → Any
-
final
def
==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
final
def
asInstanceOf[T0]: T0
- Definition Classes
- Any
-
def
clone(): AnyRef
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws( ... ) @native()
-
final
def
eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
def
equals(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
def
finalize(): Unit
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws( classOf[java.lang.Throwable] )
-
final
def
getClass(): Class[_]
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
def
hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
final
def
isInstanceOf[T0]: Boolean
- Definition Classes
- Any
-
lazy val
logger: prelude.external.Logger
- Attributes
- protected
- Definition Classes
- DirectLogging
-
val
logicalId: LogicalServiceId
A logical identifier unique in the deployment.
A logical identifier unique in the deployment. Defaults to class name.
-
final
def
ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
final
def
notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
final
def
notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
final
def
synchronized[T0](arg0: ⇒ T0): T0
- Definition Classes
- AnyRef
-
def
toString(): String
- Definition Classes
- AnyRef → Any
-
final
def
wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... ) @native()
- object Instance
-
object
Envelope extends Serializable
- Definition Classes
- ServiceActor
-
object
Event
Any statement in the protocol can be considered an Event not associated with any additional scope.
Any statement in the protocol can be considered an Event not associated with any additional scope.
- see also ServiceActor.RequestScope and Request.unapply
- Definition Classes
- ServiceActor
-
object
Request
- Definition Classes
- ServiceActor
-
object
StopEnvelope extends Envelope with Product with Serializable
- Definition Classes
- ServiceActor
-
object
Bindings
Methods to bind this service's protocol to implementations.
Methods to bind this service's protocol to implementations.
If a binding is not provided for a protocol message the message is considered unhandled. Any endpoint for the protocol message will reply with HTTP 501 Not Implemented.
// a hypothetical service for account balances final object AServiceFragment extends ServiceFragment { override def instantiate(env: InstanceEnv) = new Instance(env) { // the service event consumer is implemented using... val bindings = bindingsChain( // operations on a named entity entity(AnEntity) { case ServiceOperationOnEntity(entityId) => AnEntity.AnOperation -> accountId }, // a daemon sending Proto messages back to this service async(OrdersOverSMSBehavior) // where OrdersOverSMSBehavior being a [[ServiceActorDaemon]] ) } }
- Definition Classes
- ServiceBindings
-
object
Endpoints
- Definition Classes
- ServiceEndpoints
glngn server is a low-code business process as a service rapid development system. Conceptually similar to a programmable Microsoft Access or Apple FileMaker for scalable event sourced business services. In addition to a library, a standalone application is provided that is useful with minimal ceremony. This can be customized with a simple API. As well as deployed to a kubernetes cluster should those advantages be required.
A deployment is cluster of glngn.server.node.AppNodes serving a dynamic composition of glngn.server.ServiceFragments. Deployments are designed to be fully usable as a standalone local application or a kubernetes service.
Contact support@dogheadbone.com for support and licensing.