Skip to main content

Akka HTTP with OverLayer

Akka HTTP Setup#

This part will be focusing on setting up an Akka HTTP Server. The code will be somewhat identical to the Sangria's official docs.

Akka HTTP no OverLayer setup#

We will start with a simple Akka HTTP setup not taking account OverLayer at the moment.

Main.scala
import akka.http.scaladsl.Httpimport akka.http.scaladsl.server.Directives._import akka.http.scaladsl.server.Routeimport akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupportimport sangria.marshalling.sprayJson._import spray.json.JsValueimport /* path to file */.Schemaimport /* path to file */.Contextimport /* path to file */.Implicits._
object Main extends SprayJsonSupport {
  implicit val executionContext = system.executionContext
  // Simple Routing DSL  val route: Route = {    (post & path("graphql") & entity(as[JsValue])) { req =>      handle(req, Schema.t ???)    } ~ path(Remaining) { _ =>      getFromResource("assets/playground.html")    }  }
  // Run the server  def main(args: Array[String]): Unit = {    Http()      .newServerAt("localhost", 4000)      .bind(route)  }
  def handle(js: JsValue, schema: Schema[Context, Unit], ctx: Ctx): Route = ???}

Adding the Singletons#

Let's add the missing singletons used for the Context.

Main.scala
import ...import /* path to file */.Channelimport /* path to file */.MessageStore
object Main extends SprayJsonSupport {  // ...
  val channel = new Channel()
  val store = new MessageStore()
  val route: Route = {    (post & path("graphql") & entity(as[JsValue])) { req =>      handle(req, schema ???)    } ~ path(Remaining) { _ =>      getFromResource("assets/playground.html")    }  }
  // ...
}

Akka Websocket Setup#

Now let's setup the proper subscription through websocket.

Using the required ActorSystem.#

OverLayer required a specific behavior for the main actor to allow spawning its own actors. This can be done easily by using OverTransportLayer's .makeSystem or .behavior.

Implicits.scala (using makeSystem)
Implicits.scala
import akka.actor.typed.{ActorSystem, SpawnProtocol}import akka.stream.Materializerimport akka.actor.typed.scaladsl.Behaviorsimport io.github.dexclaimation.overlayer.OverTransportLayer
object Implicits {  implicit val actorSystem: ActorSystem[SpawnProtocol.Command] =    OverTransportLayer.makeSystem("MainActorSystem")
  implicit val materializer: Materializer =    Materializer.createMaterializer(system)}

Adding OverLayer#

Main.scala
import ...import io.github.dexclaimation.overlayer.OverTransportLayer
object Main extends SprayJsonSupport {  // ...
  val transport = OverTransportLayer(Schema.t, ()) // <- default to use `subscriptions-transport-ws`
  val route: Route = {    (post & path("graphql") & entity(as[JsValue])) { req =>      handle(req, schema, Context(store, channel))    } ~ path("graphql" / "websocket") {      transport.applyMiddleware(Context(store, channel))    } ~ path(Remaining) { _ =>      getFromResource("assets/playground.html")    }  }
  // ...}

That's it. That few lines added was all that it takes to add in OverLayer into an existing Akka HTTP GraphQL Server.

Example request#

You can immediately try this out on a GraphQL Browser IDE like graphql-playground and Apollo Sandbox.

Here is an example:

mutation {  send(msg: "Hello Friends!!", by: "Me") {    id  }}

{  "data": {    "send": {      "id": "c9e6e890-9850-4dee-a7b3-685423272c86"    }  }}