polyvariant / smithy4s-caliban   0.1.0

GitHub

Smithy4s integration for Caliban, a Scala GraphQL library.

Scala versions: 3.x 2.13

smithy4s-caliban

Smithy4s integration for Caliban.

Installation

In sbt:

libraryDependencies ++= Seq("org.polyvariant" %% "smithy4s-caliban" % version)

In scala-cli:

//> using lib "org.polyvariant::smithy4s-caliban:version"

Usage

Set up smithy4s

Follow the quickstart steps.

Write a Smithy spec

For example:

$version: "2"

namespace hello

service HelloService {
    operations: [GetHello]
}

@readonly
operation GetHello {
    input := {
        @required
        name: String
    }
    output := {
        @required
        greeting: String
    }
}

Make sure you can generate Smithy4s code for that spec.

Implement service

Implement the trait generated by Smithy4s:

import hello._
import cats.effect._

val impl: HelloService[IO] = new HelloService[IO] {
  override def getHello(name: String): IO[GetHelloOutput] =
    IO.println("hello, " + name).as(GetHelloOutput("hello, " + name))
}

Interpret to GraphQL

This is what the library will allow you to do: convert that service implementation to a GraphQL root.

import org.polyvariant.smithy4scaliban._
import caliban.GraphQL

val api: Resource[IO, GraphQL[Any]] = CalibanGraphQLInterpreter.server(impl)

This returns a Resource because it requires (and creates) a Dispatcher.

Now, the last part - you have to connect this GraphQL instance to a server. How you do it is up to you, but http4s is recommended. Here's a full example (requires caliban-http4s, tapir-json-circe and http4s-ember-server):

import caliban.Http4sAdapter
import caliban.CalibanError
import caliban.interop.tapir.HttpInterpreter
import sttp.tapir.json.circe._
import caliban.interop.cats.implicits._
import org.http4s.ember.server.EmberServerBuilder

val server: IO[Nothing] = api.evalMap { serverApi =>
  implicit val rt: zio.Runtime[Any] = zio.Runtime.default

  serverApi
    .interpreterAsync[IO]
    .map { interp =>
      Http4sAdapter.makeHttpServiceF[IO, Any, CalibanError](HttpInterpreter(interp))
    }
}
.flatMap { routes =>
  EmberServerBuilder.default[IO].withHttpApp(routes.orNotFound).build
}.useForever

This will launch a server on localhost:8080 running your Smithy spec as a GraphQL API.