Code Structure
Tenant API Code Structure
The API generates two kinds of classes: GraphQL Representational Types (GRTs), and resolver base classes, described in the Resolvers section.
For each GraphQL type, Viaduct generates a number of Kotlin classes to represent its values. These classes are found in the viaduct.api.grts
package. We generate two classes for each GraphQL type: a class representing a value of a given type, and a builder-class allowing you to construct a value of a given type. Consider this simple schema:
type User implements Node {
id: ID!
firstName: String
lastName: String
displayName: String
}
The signature of the GRT for this type would look approximately like this:
package viaduct.api.grts
class User private constructor(...): NodeObject {
suspend fun getId(alias: String? = null): GlobalID<User>
suspend fun getFirstName(alias: String? = null): String?
suspend fun getLastName(alias: String? = null): String?
suspend fun getDisplayName(alias: String? = null): String?
class Builder(ctx: ExecutionContext): DynamicValueOutputBuilder<User> {
fun id(id: GlobalID<User>): Builder
fun firstName(firstName: String?): Builder
fun lastName(lastName: String?): Builder
fun displayName(displayName: String?): Builder
override fun build(): User
}
}
NodeObject
is a tagging interface (i.e., an interface with no methods) for GRTs representing GraphQL object types. DynamicValueOutputBuilder
is an interface for builders of such types (it is parameterized on T
and defines a build
function that returns a T
).
The values from a fragment on User
(for example) are accessed through the GRT for User
. As a result, the Viaduct GRTs for object types distinguish fields that are “not set,” because they haven’t been requested for in the fragment, from fields that are in the fragment and thus are “set.” If you attempt to access a field that has not been set, a UnsetSelectionException
exception will be thrown, even if that field is nullable. Also, when you build an object-type value, you do not have to set all fields, even if those fields are non-nullable.
The GRTs for interface types are Kotlin interfaces with suspending getters (but no builders), while the GRTs for union types are simply Kotlin “tagging” interfaces (i.e., Kotlin interfaces with no members).
For GraphQL input-object types, the pattern for GRTs is similar to that for output-object types illustrated by User
. However, instead of suspending getter functions, the GRTs for input-object types use Kotlin properties for accessing fields. “Partial” input-object types are not possible: every field of an input-object GRT instance is defined (thus, UnsetSelectionException
is never thrown when accessing their fields). To achieve this invariant, builders for input-object types are stricter than those for object types: if you call build
on an InputType.Builder
instance without having set all required fields of that type, then build
will raise a runtime error. A field is “required” if it’s defined with the `!` (non-null) wrapper and it has no default value.
Viaduct is what is known as a “schema-first” GraphQL system: developers write GraphQL schema directly, and the Viaduct system generates “GraphQL representational types (GRTs)” to allow developers to read and write the types expressed by the schema.
Any single tenant module consumes only a small fraction of the central schema, so building representational types for the entire schema for every tenant is wasteful. Instead, Viaduct uses “compilation schemas”, a per-tenant-module, private view of the central schema consisting of only the schema elements used by a tenant module. This makes Viaduct builds fast and scalable by ensuring that tenant modules are built in parallel and are only rebuilt when needed.
The tenant module compilation schema is used to generate the GRTs described above. The compilation schema is a subset of the total schema visible to a tenant module, a subset generated by looking at the import statements in the tenant module’s source code. Tenant compilation schemas are always valid, self-contained GraphQL schemas.
Tenant API Code Structure
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.