(Experimental) Google APIs client code generator

Maven Central Version

⚠️ This project is in an experimental stage (with a messy code base), use with care if you want to give it a try.

Generates client code from Google's disovery document for your Scala (3) tech stack.
Currently it provides following configurations for generated code:

  • Http sources: Sttp4
  • JSON codecs: Jsoniter, ZioJson
  • JSON Array collection type: List, Vector, Array, ZioChunk

NOTE: Generated code does not include authentication.

If you're using http4s and circe you may also want to check some similar projects:

Usage

The generator can be used with any tool that can perform system calls to a command line executable or add Scala 3 dependencies (e.g. scala command line, sbt 1, sbt 2, mill, etc.).

Usage via Scala command line example

See example under example/generate.scala.

//> using scala 3.7.4
//> using dep dev.rolang::gcp-codegen::0.0.12

import gcp.codegen.*, java.nio.file.*, GeneratorConfig.*

@main def run =
  val files = Task(
    specsInput = SpecsInput.StdIn,
    config = GeneratorConfig(
      outDir = Path.of("out"),
      outPkg = "example.pubsub.v1",
      httpSource = HttpSource.Sttp4,
      jsonCodec = JsonCodec.Jsoniter,
      arrayType = ArrayType.List,
      preprocess = specs => specs
    )
  ).runAwait()
  println(s"Generated ${files.length} files")

Run example:

cat example/pubsub_v1.json | scala example/generate.scala

See output in example/out.

Command-line executable usage

Configuration parameters (currently supported):
Configuration Description Options Default
-specs Can be stdin or a path to the JSON file.
-out-dir Output directory
-out-pkg Output package
-http-source Generated http source. Sttp4
-json-codec Generated JSON codec Jsoniter, ZioJson
-jsoniter-json-type In case of Jsoniter a fully qualified name of the custom type that can represent a raw Json value
-array-type Collection type for JSON arrays List, Vector, Array, ZioChunk List
-include-resources Optional resource filter.
Jsoniter Json type and codec example

Jsoniter doesn't ship with a type that can represent raw Json values to be used for mapping of any / object types,
but it provides methods to read / write raw values as bytes (related issue).
Given that we can create a custom type with a codec which can look for example like that:

package example.jsoniter
import com.github.plokhotnyuk.jsoniter_scala.core.*

opaque type Json = Array[Byte]
object Json:
  def writeToJson[T: JsonValueCodec](v: T): Json = writeToArray[T](v)

  given codec: JsonValueCodec[Json] = new JsonValueCodec[Json]:
    override def decodeValue(in: JsonReader, default: Json): Json = in.readRawValAsBytes()
    override def encodeValue(x: Json, out: JsonWriter): Unit = out.writeRawVal(x)
    override val nullValue: Json = Array[Byte](0)

  extension (v: Json)
    def readAsUnsafe[T: JsonValueCodec]: T = readFromArray(v)
    def readAs[T: JsonValueCodec]: Either[Throwable, T] =
      try Right(readFromArray(v))
      catch case t: Throwable => Left(t)

Then pass it as argument to the code generator like -jsoniter-json-type=_root_.example.jsoniter.Json.
Since this type and codec can be shared across generated clients it has to be provided (at least for now) instead of being generated for each client to avoid duplicated / redundant code.

Examples:

Command line binaries are not published (not yet).
A command line binary can be built from the source via sbt buildCliBinary.
The output directory is modules/cli/target/bin.
E.g. on Linux the output file will be like modules/cli/target/bin/gcp-codegen-x86_64-linux.

curl 'https://pubsub.googleapis.com/$discovery/rest?version=v1' > pubsub_v1.json

# the path to the executable may be different
./modules/cli/target/bin/gcp-codegen-x86_64-linux \
  -out-dir=src/scala/main/generated \
  -specs=./pubsub_v1.json \
  -out-pkg=gcp.pubsub.v1 \
  -http-source=sttp4 \
  -json-codec=ziojson \
  -include-resources='projects.*,!projects.snapshots' # optional filters

Building and testing

Generate, compile and run tests for generated code

sbt buildCliBinary test