root
: Contains tests and nothing elsecli
: CLI driver and argument parsercore
: Tagless Final traits, SPI loaders, and core data structuresjava-async-http
: Generators forasync-http-client
java-dropwizard
: Generators for dropwizardjava-spring-mvc
: Generators for spring-mvcjava-support
: Language definitions for Java, as well as Jackson generatorsscala-akka-http
: Generators forakka-http
clients and serversscala-dropwizard
: Generators for dropwizardscala-http4s
: Generators forhttp4s
clients and serversscala-support
: Language definitions for Scala, as well as circe and Jackson generators
- Readability
- Maintainability
- Testability
- Defer effects
- Typesafe accessors for Java function calls
It is difficult to tell if the code generated by the tool is functional and type sound by structure alone. As unit tests are not enough, integration tests actually run guardrail as a CLI tool to generate complete clients and servers, ensuring everything works as expected.
The projects defined at modules/sample-*
contain:
target/generated
: Sources generated byrunScalaExample
orrunJavaExample
src/main
: Support definitions for generated codesrc/test
: Manually written integration tests against the generated code. These tests are run by theruntimeScalaSuite
,runtimeJavaSuite
, or the integrationtestSuite
command.
By running guardrail, then attempting to compile the generated code, then running integration tests against the generated code, we can ensure quality.
Adding new specifications is accomplished by:
- creating a file in
modules/sample/src/main/resources
- adding an entry in
exampleCases
defined inbuild.sbt
. The available flags are largely undocumented, so reading the parser is necessary.
val exampleCases: List[ExampleCase] = List(
ExampleCase(sampleResource("additional-properties.yaml"), "additionalProperties"),
ExampleCase(sampleResource("petstore.json"), "examples").args("--import", "support.PositiveLong"),
ExampleCase(sampleResource("polymorphism-nested.yaml"), "polymorphismNested").frameworks(Set("akka-http", "http4s"))
)
- First argument has to point to the newly added specification file.
sampleResource
looks up the specification inmodules/sample/src/main/resources
- Second argument defines what package to put the specification into (For regression tests,
issues.issue1234
) .args(...)
is variadic, and concatenates the specified args directly to the end of your command.frameworks(...)
is the set of frameworks that this file should be run against
Define your tests in ./modules/sample-*/src/test/scala
make sure to use
imports corresponding the previously defined packageName
Use the runtimeSuite
command inside of an SBT session to run code generation and execute the tests
- Scalameta Quasiquotes: https://github.com/scalameta/scalameta/blob/master/notes/quasiquotes.md