Multiplexed Endpoints

This algebra provides vocabulary to define endpoints multiplexing several requests and responses.

API documentation

In general, each possible resource or action supported by a service is exposed through a specific endpoint, taking a specific request type and a specific response type.

However, in some cases it is useful to use a same endpoint to manage several resources or actions. We call them multiplexed endpoints.

The algebra enriches the Endpoints algebra with the concept of MuxEndpoint[Req, Resp, Transport], defining a multiplexed endpoint with a request containing a type Req, a response of type Resp, and serializing data to and from the Transport type.

For instance, the type MuxEndpoint[Command, Event, Json] defines and endpoint whose requests contain Command values, whose responses contain Event values, and which serialize commands and events to Json.

Since the type of a response can vary according to the type of specific request, multiplexed endpoints require that request types extend the MuxRequest type:

val users: MuxEndpoint[Command, Event, Json] =
  muxEndpoint[Command, Event, Json](
    post(path / "users", jsonRequest[Json]),
    ok(jsonResponse[Json])
  )

// Types of commands
sealed trait Command extends MuxRequest
final case class CreateUser(name: String) extends Command {
  type Response = UserCreated
}
final case class DeleteUser(id: Long) extends Command {
  type Response = UserDeleted
}

// Types of responses
trait Event
case class UserCreated(id: Long) extends Event
case class UserDeleted(id: Long) extends Event

Note that the Command request type extends MuxRequest and that each concrete Command refines its Response type member to refer to a concrete Event type.

Typically, client interpreters fix the MuxEndpoint[Req, Resp, Transport] type to be a function from Req to Future[Req#Response], so that calling users(CreateUser("Alice")) (statically) returns a Future[CreatedUser], and calling users(DeleteUser(42)) returns a Future[DeletedUser].