Schemas
In Viaduct, a schema describes the GraphQL surface that a request can access. In the Star Wars demo, we register two schema IDs — one public and one with extra fields — and select between them at runtime based on scopes.
What a schema is
- A set of SDL files (
*.graphqls) discovered by Viaduct under a package prefix. - A schema ID that names a concrete slice of the overall SDL (for example, public vs. public-with-extras).
- A scope configuration that controls which requests can see each slice.
The Star Wars demo defines two schema IDs:
PUBLIC_SCHEMA— the default public surface.PUBLIC_SCHEMA_WITH_EXTRAS— includes everything fromPUBLIC_SCHEMAplus extra fields marked with@scope(to: ["extras"]).
Where schemas are registered
Schemas are registered in configuration, providing scope bindings and SDL discovery settings (package prefix
and resource regex). Example (excerpt adapted from ViaductConfiguration.kt):
schemaRegistrationInfo = SchemaRegistrationInfo(
scopes = listOf(
DEFAULT_SCHEMA_ID.toSchemaScopeInfo(),
EXTRAS_SCHEMA_ID.toSchemaScopeInfo(),
),
packagePrefix = "com.example.starwars", // Scan the entire com.example.starwars package for graphqls resources
resourcesIncluded = ".*\\.graphqls"
),
packagePrefix: where Viaduct scans for generated types/resolvers.resourcesIncluded: which SDL files to include.scopes: which runtime scopes activate each schema ID.
Organizing SDL files
Place your GraphQL SDL files under the configured resources path so they are included by resourcesIncluded. Keep
entities modular (for example, character.graphqls, film.graphqls, species.graphqls) and use directives like
@scope, @idOf, and @oneOf where appropriate.
Example (fragment)
type Planet implements Node @scope(to: ["default"]) @resolver {
"""
The ID of an object
"""
id: ID!
"""
The name of this planet.
"""
name: String
"""
The diameter of this planet in kilometers.
"""
diameter: Int
"""
The number of standard hours it takes for this planet to complete a single
rotation on its axis.
"""
rotationPeriod: Int
"""
The number of standard days it takes for this planet to complete a single orbit
of its local star.
"""
orbitalPeriod: Int
"""
A number denoting the gravity of this planet, where "1" is normal or 1 standard
G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs.
"""
gravity: Float
"""
The average population of sentient beings inhabiting this planet.
"""
population: Float
"""
The percentage of the planet surface that is naturally occurring water or bodies
of water.
"""
surfaceWater: Float
"""
The ISO 8601 date format of the time that this resource was created.
"""
created: String
"""
The ISO 8601 date format of the time that this resource was edited.
"""
edited: String
"""
The residents of this planet.
"""
terrains: [String]
"""
The films that this planet has appeared in.
"""
climates: [String]
"""
The residents of this planet.
"""
residents(limit: Int): [Character!] @resolver
"""
The films that this planet has appeared in.
"""
films(limit: Int): [Film!] @resolver
}
Fields like
filmare typically resolved by field/batch resolvers, not embedded in SDL logic.
Evolving the schema
To add a field that should exist only in the extras slice:
- Declare it in SDL with a scope:
extend type Species @scope(to: ["extras"]) {
culturalNotes: String @resolver
rarityLevel: String @resolver
specialAbilities: [String] @resolver
technologicalLevel: String @resolver
}
- Ensure the schema ID associated with
extrasis registered (PUBLIC_SCHEMA_WITH_EXTRAS). - The controller will route requests that include the extras scope to that schema ID.
To add a new entity:
- Define the type and relationships in SDL.
- Implement node/field (and batch if needed) resolvers.
- Emit typed IDs with
ctx.globalIDFor(Type.Reflection, internalId). - Write integration tests that hit both schema IDs if visibility differs.
Testing and troubleshooting
- Validate that the expected fields appear in introspection under each schema ID.
- Run end-to-end queries for both public and extras slices.
- Confirm that resolvers are wired and batched correctly when many parents are selected.
- Log the chosen
schemaIdand active scopes for each request.
Do and don’t
- Do register schema IDs with clear scope sets (public vs. public + extras).
- Do keep SDL modular and use directives for visibility and type-safety.
- Don’t rely on a single “mega schema” and conditional logic inside resolvers to hide fields.
- Don’t mix raw IDs with Global IDs; declare
@idOfwhere applicable.
Feedback
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.