Sangria GraphQL Library for Scala
repository·main·Indexed 24 days ago
https://github.com/sangria-graphql/sangriaA spec-compliant GraphQL library for Scala that enables the creation of GraphQL servers compatible with Apollo, Relay, and GraphiQL. It provides a comprehensive AST hierarchy for documents, schemas, and input values, along with tools for JSON marshalling via sangria-circe, execution result resolution, and error reporting using SourceMapper.
What's inside Sangria
- After a release has been triggered, you can finalize the documentation by updating the GitHub release page. A draft release should be automatically prepared by the CI. You must edit this draft to set the correct released version and complete the release notes before saving.
Install Sangria via SBT
mainTo add Sangria to your Scala project using SBT, add the following dependency to your
libraryDependencies. Replace<latest version>with the current version of Sangria.libraryDependencies += "org.sangria-graphql" %% "sangria" % "<latest version>"Release a new version of Sangria
mainSangria uses an automated release process triggered by Git tags. To initiate a release, create a new annotated Git tag where the version string must start with a
v. Once the tag is pushed to the origin, the CI pipeline will handle the release automatically. Note that publishing artifacts to Maven Central may take some time after the pipeline starts.git tag -a v0.1.0 -m "v0.1.0" git push origin v0.1.0Run Sangria benchmarks with sbt-jmh
mainSangria benchmarks are executed using OpenJDK JMH and integrated into the build system via
sbt-jmh.To run a full, standard benchmark suite, use:
jmh:runWhen developing or debugging a new benchmark, you can use specific flags to reduce execution time by limiting iterations, warmups, forks, and threads.
Use Sangria with Circe JSON marshalling
mainTo use Sangria with the Circe JSON library for marshalling, include the
sangria-circedependency in your SBT configuration.libraryDependencies += "org.sangria-graphql" %% "sangria-circe" % "1.3.2"Understand the GraphQL AST hierarchy
mainThe Sangria AST is built on a hierarchy of traits. All nodes implement
AstNode, which provides alocation(the lexical position in the source code).Core abstractions:
- Definition: The building blocks of a
Document. IncludesOperationDefinition(executable operations like queries/mutations) andFragmentDefinition(reusable selection sets). - Selection: Components of a query. A
SelectionContainer(like aFieldorInlineFragment) contains aselections: Vector[Selection]. - Type: Represents GraphQL types.
Typecan be aNamedType,NonNullType, orListType. You can use.namedTypeon anyTypeto recursively find the underlyingNamedType(stripping away list and non-null wrappers). - Value: Represents input values (scalars like
IntValue,StringValue,BooleanValue, or complex types likeListValueandObjectValue).
- Definition: The building blocks of a
How GraphQL Types and Input Types relate
mainSangria distinguishes between
OutputType(used for data returned by the server) andInputType(used for data provided by the client, like arguments or input objects).LeafType: The most basic types, such asScalarTypeorEnumType.CompositeType: Types that contain other fields, such asObjectType,InterfaceType, orUnionType.InputType: A hierarchy for client-side data, includingScalarType,EnumType,InputObjectType, and wrappers likeListInputTypeorOptionInputType.
How Schema, ObjectType, and InputObjectType relate
mainA
Schemais the top-level container for a GraphQL service. It defines the entry points for execution:query,mutation, andsubscription(all of which areObjectTypes).ObjectType: Represents the data structures returned by the server. They contain fields that resolve to other types.InputObjectType: Represents the data structures sent by the client as arguments to fields or mutations.Schema: Composes these types and includes global configuration likedirectives,validationRules, andadditionalTypes(used to ensure all types in the graph are known).
Understand the Context object in Sangria
mainThe
Context[Ctx, Val]class is the primary object provided during field resolution. It encapsulates everything a resolver needs to know about the current execution state for a specific field.Key Properties:
value: The object (parent) to which the current field belongs.ctx: The user-provided execution context (passed to Sangria's execution method).args: The arguments provided for this field.schema: The GraphQL schema being executed.field: The specificFieldbeing resolved.path: TheExecutionPathrepresenting the location of this field in the query.marshaller: TheResultMarshallerused for encoding results.sourceMapper: An optionalSourceMapperfor mapping errors back to source locations.deprecationTracker: An optional tracker for handling deprecated fields.
Mental Model: Think of
Contextas the 'environment' for a single field. It bridges the gap between the raw GraphQL query (AST), the schema definitions, and your application's domain data (value).Define GraphQL Schema AST nodes
mainThe AST includes types for representing a GraphQL schema (the type system). These are categorized as:
- TypeSystemDefinition: Definitions of types (e.g.,
ScalarTypeDefinition,ObjectTypeDefinition,InterfaceTypeDefinition,UnionTypeDefinition,EnumTypeDefinition,InputObjectTypeDefinition). - TypeSystemExtensionDefinition: Extensions to existing types (e.g.,
ObjectTypeExtensionDefinition,InterfaceTypeExtensionDefinition, etc.). - SchemaDefinition: The root definition of a schema, specifying
operationTypes(Query, Mutation, Subscription).
- TypeSystemDefinition: Definitions of types (e.g.,
Create a Hello World GraphQL application
mainThis example demonstrates how to define a simple GraphQL schema using Sangria, a
Querytype with a singlehellofield, and execute a query using theExecutor. This example usessangria-circefor JSON marshalling.import sangria.schema._ import sangria.execution._ import sangria.macros._ import sangria.marshalling.circe._ import scala.concurrent.ExecutionContext.Implicits.global val QueryType = ObjectType("Query", fields[Unit, Unit]( Field("hello", StringType, resolve = _ => "Hello world!") )) val schema = Schema(QueryType) val query = graphql"{ hello }" val result = Executor.execute(schema, query) result.foreach(res => println(res.spaces2))Configure the Sangria Parser with ParserConfig
mainThe
ParserConfigclass allows you to customize how the GraphQL parser behaves, specifically regarding source mapping, comment parsing, and location tracking. You can create a custom configuration by instantiatingParserConfigor by using the provided helper methods on thedefaultinstance to derive new configurations.Configuration Options
Option Type Default Description experimentalFragmentVariablesBooleanfalseEnables experimental support for fragment variables. sourceIdFnParserInput => StringParserConfig.defaultSourceIdFnA function to generate a unique identifier for the source code. sourceMapperFnCodeSourceToSourceMapperFunctionParserConfig.defaultSourceMapperFnA function that maps a source identifier and ParserInputto aSourceMapper.parseLocationsBooleantrueWhether to parse location information (line/column) into the AST. parseCommentsBooleantrueWhether to parse comments into the AST.