/scala-json-rpc

Scala Implementation of JSON RPC 2.0 Protocol

Primary LanguageScala

scala-json-rpc

Scala Implementation of JSON RPC 2.0 based on circe and Akka Streams.

Features automatic derivation (using macros) of abstract traits describing the protocol.

Compiles to JVM and JavaScript via Scala.js

Getting Started

Add the following to your sbt build definition

// Add flatmap bintray repo
resolvers += Resolver.bintrayRepo("flatmap", "maven")

// For scala.js projects
libraryDependencies += "net.flatmap" %%% "jsonrpc" % "0.4.0"

// For ordinary Scala projects
libraryDependencies += "net.flatmap" %% "jsonrpc" % "0.4.0"

Defining a Protocol

Define your server and client interfaces as Scala traits:

trait ExampleServer {
  // all jsonrpc methods must either return `Unit` or `Future[T]`
  def sayHello(s: String): Future[String]
  
  // Custom Names
  @JsonRPC.Named("class")
  def clazz(i: Int): Unit
  
  // Sub-Protocols
  // Type 'Other' will be treated as protocol with
  // "other/" prefix on all methods
  @JsonRPC.Namespace("other/")
  def foo: Other    
}
trait ExampleClient {
  def foo: Future[Int]
}

Deriving Implementations

Implement the client:

class ExampleClientImpl(server: ExampleServer) {
  def foo: Future[Int] = 
    server.sayHello("world").map(_.length)  
}

Derive message-flow representations of the server and the client:

val local: Flow[RequestMessage,Response,Promise[Option[ExampleClient]]]  =
  Local[ExampleClient]

val remote: Flow[Response,RequestMessage,ExampleServer] =
  Remote[ExampleServer](Id.standard) // Use standard message Ids

Opening a connection

Prepare your connection

val connectionFlow: Flow[ByteString,ByteString,Connection[ExampleClient,ExampleServer]] =
  Connection.bidi(local,remote,(srv: ExampleServer) => new ExampleClientImpl(srv))

Use it:

val in: Source[ByteString,Any] =  ... // input stream
val out: Sink[ByteString,Any] =   ... // output stream 
val connection = in.viaMat(connectionFlow)(Keep.right).to(out).run()

Using with HTTP or WebSockets

To use websockets or http use Connection.bidi(...,framing = Framing.none) and connect flow to websockets or http requests via Connection.open

License

MIT