Scala is an excellent language for writing GraphQL apps, especially with the awesome Sangria library for writing GraphQL servers by Oleg Ilyenko. Scala is a powerful language, combining object oriented and functional programming concepts to make writing complex applications easy. The functional programming aspects of Scala are especially helpful when writing GraphQL schemas, allowing you to declare resolvers without any boilerplate.

With Scala.js, you can now use Scala to write client-side apps, by writing Scala code that compiles to JavaScript that runs in your browser. With a straightforward interop layer between Scala and JavaScript, it’s easy to use frameworks like React and Angular to create Scala.js apps. And starting today, Apollo joins in the fun with a new library for using Apollo Client with React in Scala: react-apollo-scalajs!

Adding the react-apollo graphql HOC in Scala

As its name suggests, react-apollo-scalajs provides the glue to use Apollo Client with React in your Scala.js app. Beyond providing static typing facades for Apollo Client, react-apollo-scalajs includes layers that allow you to use Apollo Client through idiomatic Scala code. For example, results of queries are returned as Scala Futures and query results can be implicitly converted into fragments they can be viewed as.

Through the excellent apollo-codegen tool, which is currently used for generating static types for Swift, TypeScript, and Flow, you can now generate Scala case classes which represent the responses of GraphQL queries you will be running in your app. With strong query typing, most issues can be caught at compile-time, with react-apollo-scalajs performing extra type checks as you set up React components to receive query results.

A simple example

Download and run the example on GitHub!

To demonstrate how you can use react-apollo-scalajs , let’s go through a quick example of putting together an app with queries and mutations targeting a GraphQL server on Apollo Launchpad.

First, set up your project by installing the Scala.js plugin and the necessary library dependencies.

In your project/plugins.sbt add the Scala.js plugin and the Scala.js Bundler plugin (for Webpack-based bundling):

addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.18") addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.7.0")

And in your build.sbt specify the Scala version, add NPM and Scala library dependencies, and configure the code generator:

enablePlugins(ScalaJSBundlerPlugin) resolvers += "Apollo Bintray" at "https://dl.bintray.com/apollographql/maven/" libraryDependencies += "com.apollographql" %%% "react-apollo-scalajs" % "0.1.0" libraryDependencies += "me.shadaj" %%% "slinky-web" % "0.1.0" npmDependencies in Compile += "react" -> "15.6.1" npmDependencies in Compile += "react-dom" -> "15.6.1" npmDependencies in Compile += "react-apollo" -> "1.4.8" scalaJSUseMainModuleInitializer := true val namespace = "com.apollographql.scalajs" (sourceGenerators in Compile) += Def.task { import scala.sys.process._ val out = (sourceManaged in Compile).value out.mkdirs() Seq( "apollo-codegen", "generate", ((sourceDirectory in Compile).value / "graphql").getAbsolutePath + "/*.graphql", "--schema", (baseDirectory.value / "schema.json").getAbsolutePath, "--target", "scala", "--namespace", namespace, "--output", (out / "graphql.scala").getAbsolutePath ).! Seq(out / "graphql.scala") } watchSources ++= ((sourceDirectory in Compile).value / "graphql" ** "*.graphql").get

Eventually, the source generators configuration at the end of the file will be moved into an SBT plugin, but for now it is necessary to include this in all projects.

Creating a UI

Before we jump into using GraphQL for loading our data, let’s start by setting up a simple React UI to verify that our setup works. Create a file src/main/scala/com/apollographql/scalajs/Main.scala where we’ll put the initializer for our application. For using React in Scala, we’ll use Slinky, which makes React in Scala look very similar to React in plain JavaScript.

package com.apollographql.scalajs import me.shadaj.slinky.web.ReactDOM import me.shadaj.slinky.web.html._ // imports tags, such as "h1" import scala.scalajs.js.JSApp import org.scalajs.dom.{document, html} import scala.scalajs.js object Main extends JSApp { override def main(): Unit = { // called when the app launches val reactContainer = document.createElement("div") document.body.appendChild(reactContainer) ReactDOM.render( h1("hello!"), // this is Scala's version of JSX! reactContainer ) } }

If you run sbt fastOptJS::startWebpackDevServer you should be able to navigate to http://localhost:8080/webpack-dev-server, select the main-bundle and see your app running live!

Adding GraphQL

Now that we have a simple app set up, we can add use GraphQL to load data for it! For this example, we will be running GraphQL queries against the Apollo Launchpad at https://launchpad.graphql.com/1jzxrj179, loading and displaying posts in our app. First, we add the GraphQL query for loading all posts. In src/main/graphql/posts.graphql add the query:

query AllPosts { posts { id title votes } }

If you run sbt/compile you’ll see that the code generator kicks in (make sure you have previously run npm i -g apollo-codegen ) and emits static types for our query to target/scala-2.12/src_managed/main/graphql.scala . We can now use these static types to power our React app!

Wiring GraphQL data into a component through react-apollo-scalajs is just like using Apollo in your JS code. First, we create a component to receive the data from our query. In src/main/scala/com/apollographql/scalajs/PostsView.scala we set up a new component:

package com.apollographql.scalajs import me.shadaj.slinky.core.StatelessComponent import me.shadaj.slinky.core.facade.ReactElement import me.shadaj.slinky.web.html._ import scala.scalajs.js import scala.scalajs.js.annotation.ScalaJSDefined object PostsView extends StatelessComponent { type Props = AllPostsQuery.Props // we use the static Props type from our generated code as the props for // this is where we create the definition class, which maps to an ES6 class for defining a component @ScalaJSDefined class Def(jsProps: js.Object) extends Definition(jsProps) { override def render(): ReactElement = { div( props.data.map[ReactElement] { d => // if we have a result d.posts.toList.flatten.flatten.map { post => // for each not-null post (we use flattens here to remove the null values) div(key := post.id.toString)( // render the post h1(post.title.getOrElse[String]("Unknown title")), h2(post.votes.getOrElse(0).toString) ) } }.getOrElse[ReactElement](h1("loading!")) ) } } // wire the component to our query using the familiar graphql method val WithData = graphql(AllPostsQuery)(this) }

And that’s it! You now have a React component that’s wired to a GraphQL query. The last step is to adjust our application initializer to wrap the application inside an ApolloProvider and configure Apollo Client to run queries against the Launchpad server.

First, at the top of our main method, we initialize Apollo Client:

val client = ApolloClient(ApolloClientOptions( networkInterface = Some(createNetworkInterface(NetworkInterfaceOptions( uri = Some("https://1jzxrj179.lp.gql.zone/graphql") ))) ))

Then we replace the contents inside ReactDOM.render to render our new component inside an ApolloProvider wrapper.

ReactDOM.render( ApolloProvider(ApolloProvider.Props(client))( div( PostsView.WithData(()) // we pass in () because there are no variables for the query ) ), reactContainer )

If you run sbt fastOptJS::startWebpackDevServer again and reload the application page you should see a working GraphQL app, showing “Loading” and then displaying the posts data!

It works!