Type-safe GraphQL for Kotlin

Hey guys. I’ve recently enabled the Manifold Java compiler plugin for use with Kotlin and other JVM languages. I’ve got a sample Kotlin application that could use some more experienced Kotlin eyeballs for review and comment. The application’s focus is GraphQL, however its purpose is to demonstrate how Kotlin can use Manifold to directly and type-safely access other resource types such as JSON, GraphQL, XML, Templates, Javascript, etc. My experience with Kotlin is limited, however, so feedback from Kotlin folks would be great. Thanks!

Note, only Manifold’s core metaprogramming project is designed for use with Kotlin. Manifold extension projects are currently Java-only features.

2 Likes

Not clear how this solution is different from KGraphQL, for example.

Code such as

val data = execute.getData<Any>()

in the example also doesn’t convince me much in type-safety of that solution. If the goal of the solution is to generate type-safe clients, that’s fine, but it should be stated somewhere.

Looking at the Manifold itself, it seems like this plugin may be useful to Java developers, but most of the features it provides already exist in Kotlin, so some examples of how a Kotlin developer could benefit from it would be nice.

GraphQL is itself a DSL, we don’t need yet another DSL to approximate it inside Kotlin as with KGraphQL. The central goal of Manifold is to bridge DSLs directly and type-safely to the language via the type system. Thus what is unique about Manifold is that it provides direct access to GraphQL. There are no code generation steps. No DSLs. No data classes to maintain. No annotations. In the IDE you can make changes to GraphQL and instantly use the changes with code completion etc. in Kotlin without a compilation step. You can rename/refactor GraphQL references from Kotlin and GraphQL files as well as find usages, navigate, etc. So it’s quite a bit different.

Manifold GraphQL is probably best for client usage. But it is really a means of working directly with GraphQL types and queries, regardless of context. For instance, the sample app uses it for data/setup on the server and for queries and mutations on the client.

The execute.getData() call is the server’s one call to access the results of executing a query. Since that is the central dispatch of all results, there is no “type-safety” to be had; it’s just data at this point.

At a high level Manifold is divided into two components: Type Manifolds and Extensions. As you point out the extensions target Java exclusively and a few of the them are already supported in Kotlin, such as extension methods and operator overloading. Many more are not, however. These include:

The sample GraphQL application demonstrates the other half of Manifold – the Type Manifold. These are Java type system extensions which make them accessible, albeit indirectly, from Kotlin. Read more about type manifolds here: https://github.com/manifold-systems/manifold/tree/master/manifold-core-parent/manifold

2 Likes

I am not sure I agree with it. HTML is DSL as well and JSON. But we still need language interface for them.

Type manifolds are not an either/or proposition; definitely not a panacea. However, in my view many use-cases involving DSLs are better suited with type manifolds. Generally, if the DSL duplicates the system of record, it’s probably better as a type manifold. For instance, if an API is published as JSON, GraphQL, or what have you, type manifolds are likely more suitable. The main idea is to avoid reinventing the wheel with redundancies such as in-language DSLs, instead keep it simple and use the primary DSL directly.

Regarding HTML, I would say a DSL is sometimes the inversion of the right solution. For many cases it’s probably best to use a type-safe template where HTML is the base content with Kotlin as the embedded logic, see Manifold templates. Again, the idea is to use the real DSL – use HTML!

Type-safely embedding other languages such as JSON, GraphQL, and HTML directly in Kotlin as declarations and expressions is also quite useful. Manifold fragments achieve this with Java: