Overview
The CLI Starter demonstrates the simplest possible Viaduct application. It executes GraphQL queries from the command line and prints the results. This tutorial is perfect for understanding the core concepts of Viaduct without the complexity of HTTP servers.What You’ll Learn
- How to create a Viaduct instance using
BasicViaductFactory - How to define GraphQL schema and resolvers
- How to execute GraphQL queries programmatically
- Understanding Viaduct’s module-based architecture
Prerequisites
- Java JDK 21 installed
JAVA_HOMEenvironment variable set correctly orjavain your PATH
Project Structure
package com.example.viadapp.resolvers
import com.example.viadapp.resolvers.resolverbases.QueryResolvers
import viaduct.api.Resolver
@Resolver
class GreetingResolver : QueryResolvers.Greeting() {
override suspend fun resolve(ctx: Context): String {
return "Hello, World!"
}
}
@Resolver
class AuthorResolver : QueryResolvers.Author() {
override suspend fun resolve(ctx: Context): String {
return "Brian Kernighan"
}
}
@ResolverQueryResolvers.Greeting())resolve method is suspendable, supporting Kotlin coroutinesSet up the Viaduct instance and execute queries in
src/main/kotlin/com/example/viadapp/ViaductApplication.kt:package com.example.viadapp
import com.fasterxml.jackson.databind.ObjectMapper
import kotlinx.coroutines.runBlocking
import viaduct.service.BasicViaductFactory
import viaduct.service.TenantRegistrationInfo
import viaduct.service.api.ExecutionInput
fun main(argv: Array<String>) {
// Create a Viaduct engine using BasicViaductFactory
val viaduct = BasicViaductFactory.create(
tenantRegistrationInfo = TenantRegistrationInfo(
tenantPackagePrefix = "com.example.viadapp"
)
)
// Create an execution input with query from args or default
val executionInput = ExecutionInput.create(
operationText = argv.getOrNull(0) ?: """
query {
greeting
}
""".trimIndent(),
variables = emptyMap(),
)
// Execute the query
val result = runBlocking {
viaduct.execute(executionInput)
}
// Print the result in JSON format
val mapper = ObjectMapper().writerWithDefaultPrettyPrinter()
println(mapper.writeValueAsString(result.toSpecification()))
}
BasicViaductFactory.create() automatically discovers schemas and resolverstenantPackagePrefix tells Viaduct where to find your resolver classesExecutionInput.create() builds the query execution contextviaduct.execute() runs the query and returns resultsresult.toSpecification() converts to standard GraphQL JSON formatHow It Works
- Schema Generation: Viaduct scans
src/main/viaduct/schema/for.graphqlsfiles - Code Generation: During compilation, Viaduct generates resolver base classes from your schema
- Resolver Discovery: At runtime, Viaduct discovers all
@Resolverannotated classes in your tenant package - Query Execution: When you call
viaduct.execute(), it:- Parses the GraphQL query
- Validates it against the schema
- Executes the appropriate resolvers
- Returns the result in GraphQL specification format
Next Steps
- Explore the Jetty Starter Tutorial to learn how to serve GraphQL over HTTP
- Check out the Star Wars Tutorial for a comprehensive example with complex data models
- Read the Getting Started Guide for more details on Viaduct concepts