mochi/schema

Core schema types and execution context for GraphQL.

This module provides:

ExecutionContext with DataLoaders

// Create context with multiple loaders
let ctx = schema.execution_context(types.to_dynamic(dict.new()))
  |> schema.with_loaders([
    #("pokemon", pokemon_loader),
    #("trainer", trainer_loader),
  ])

// Load by ID (handles context threading automatically)
let #(ctx, pokemon) = schema.load_by_id(ctx, "pokemon", 25)
let #(ctx, trainers) = schema.load_many_by_id(ctx, "trainer", [1, 2, 3])

Schema Building

let my_schema = schema.schema()
  |> schema.query(query_type)
  |> schema.mutation(mutation_type)
  |> schema.add_type(schema.ObjectTypeDef(user_type))
  |> schema.add_directive(auth_directive)

Types

pub type ArgumentDefinition {
  ArgumentDefinition(
    name: String,
    description: option.Option(String),
    arg_type: FieldType,
    default_value: option.Option(dynamic.Dynamic),
  )
}

Constructors

Custom directive definition

pub type DirectiveDefinition {
  DirectiveDefinition(
    name: String,
    description: option.Option(String),
    arguments: dict.Dict(String, ArgumentDefinition),
    locations: List(DirectiveLocation),
    is_repeatable: Bool,
    handler: option.Option(
      fn(dict.Dict(String, dynamic.Dynamic), dynamic.Dynamic) -> Result(
        dynamic.Dynamic,
        String,
      ),
    ),
  )
}

Constructors

Handler function for custom directives Takes the directive arguments and field value, returns modified value or error

pub type DirectiveHandler =
  fn(dict.Dict(String, dynamic.Dynamic), dynamic.Dynamic) -> Result(
    dynamic.Dynamic,
    String,
  )

Locations where a directive can be used

pub type DirectiveLocation {
  QueryLocation
  MutationLocation
  SubscriptionLocation
  FieldLocation
  FragmentDefinitionLocation
  FragmentSpreadLocation
  InlineFragmentLocation
  VariableDefinitionLocation
  SchemaLocation
  ScalarLocation
  ObjectLocation
  FieldDefinitionLocation
  ArgumentDefinitionLocation
  InterfaceLocation
  UnionLocation
  EnumLocation
  EnumValueLocation
  InputObjectLocation
  InputFieldDefinitionLocation
}

Constructors

  • QueryLocation
  • MutationLocation
  • SubscriptionLocation
  • FieldLocation
  • FragmentDefinitionLocation
  • FragmentSpreadLocation
  • InlineFragmentLocation
  • VariableDefinitionLocation
  • SchemaLocation
  • ScalarLocation
  • ObjectLocation
  • FieldDefinitionLocation
  • ArgumentDefinitionLocation
  • InterfaceLocation
  • UnionLocation
  • EnumLocation
  • EnumValueLocation
  • InputObjectLocation
  • InputFieldDefinitionLocation
pub type EnumType {
  EnumType(
    name: String,
    description: option.Option(String),
    values: dict.Dict(String, EnumValueDefinition),
  )
}

Constructors

pub type EnumValueDefinition {
  EnumValueDefinition(
    name: String,
    description: option.Option(String),
    value: dynamic.Dynamic,
    is_deprecated: Bool,
    deprecation_reason: option.Option(String),
  )
}

Constructors

Context for GraphQL execution, including DataLoader instances

pub type ExecutionContext {
  ExecutionContext(
    user_context: UserContext,
    data_loaders: dict.Dict(
      String,
      dataloader.DataLoader(dynamic.Dynamic, dynamic.Dynamic),
    ),
    middleware_fn: option.Option(
      fn(
        String,
        FieldDefinition,
        ResolverInfo,
        fn(ResolverInfo) -> Result(dynamic.Dynamic, String),
      ) -> Result(dynamic.Dynamic, String),
    ),
    telemetry: option.Option(TelemetryContext),
    telemetry_fn: option.Option(fn(SchemaEvent) -> Nil),
  )
}

Constructors

pub type FieldDefinition {
  FieldDefinition(
    name: String,
    description: option.Option(String),
    field_type: FieldType,
    arguments: dict.Dict(String, ArgumentDefinition),
    resolver: option.Option(
      fn(ResolverInfo) -> Result(dynamic.Dynamic, String),
    ),
    is_deprecated: Bool,
    deprecation_reason: option.Option(String),
    topic_fn: option.Option(
      fn(args.Args, ExecutionContext) -> Result(String, String),
    ),
    rich_resolver: option.Option(
      fn(ResolverInfo) -> Result(
        dynamic.Dynamic,
        #(
          String,
          option.Option(dict.Dict(String, dynamic.Dynamic)),
        ),
      ),
    ),
  )
}

Constructors

A guard function that runs before the resolver. Returns Ok(Nil) to allow the resolver to proceed, or Error(message) to reject.

pub type FieldGuard =
  fn(ResolverInfo) -> Result(Nil, String)
pub type FieldType {
  NonNull(inner: FieldType)
  List(inner: FieldType)
  Named(name: String)
}

Constructors

pub type InputFieldDefinition {
  InputFieldDefinition(
    name: String,
    description: option.Option(String),
    field_type: FieldType,
    default_value: option.Option(dynamic.Dynamic),
  )
}

Constructors

pub type InputObjectType {
  InputObjectType(
    name: String,
    description: option.Option(String),
    fields: dict.Dict(String, InputFieldDefinition),
  )
}

Constructors

pub type InterfaceType {
  InterfaceType(
    name: String,
    description: option.Option(String),
    fields: dict.Dict(String, FieldDefinition),
    resolve_type: option.Option(
      fn(dynamic.Dynamic) -> Result(String, String),
    ),
  )
}

Constructors

Function type for middleware execution - avoids circular dependency with middleware.gleam

pub type MiddlewareFn =
  fn(
    String,
    FieldDefinition,
    ResolverInfo,
    fn(ResolverInfo) -> Result(dynamic.Dynamic, String),
  ) -> Result(dynamic.Dynamic, String)
pub type ObjectType {
  ObjectType(
    name: String,
    description: option.Option(String),
    fields: dict.Dict(String, FieldDefinition),
    interfaces: List(InterfaceType),
  )
}

Constructors

pub type Resolver =
  fn(ResolverInfo) -> Result(dynamic.Dynamic, String)

Information passed to field resolvers.

args is the typed view; arguments is the legacy raw dict. New resolvers should read via args.get_string(info.args, "id") etc. arguments is kept so existing resolvers keep compiling, and so callers that need to forward the raw dict can.

pub type ResolverInfo {
  ResolverInfo(
    parent: option.Option(dynamic.Dynamic),
    arguments: dict.Dict(String, dynamic.Dynamic),
    args: args.Args,
    context: ExecutionContext,
    info: dynamic.Dynamic,
  )
}

Constructors

pub type RichResolver =
  fn(ResolverInfo) -> Result(
    dynamic.Dynamic,
    #(String, option.Option(dict.Dict(String, dynamic.Dynamic))),
  )
pub type RichResolverPayload =
  #(String, option.Option(dict.Dict(String, dynamic.Dynamic)))
pub type ScalarType {
  ScalarType(
    name: String,
    description: option.Option(String),
    serialize: fn(dynamic.Dynamic) -> Result(
      dynamic.Dynamic,
      String,
    ),
    parse_value: fn(dynamic.Dynamic) -> Result(
      dynamic.Dynamic,
      String,
    ),
    parse_literal: fn(dynamic.Dynamic) -> Result(
      dynamic.Dynamic,
      String,
    ),
  )
}

Constructors

pub type Schema {
  Schema(
    query: option.Option(ObjectType),
    mutation: option.Option(ObjectType),
    subscription: option.Option(ObjectType),
    types: dict.Dict(String, TypeDefinition),
    directives: dict.Dict(String, DirectiveDefinition),
    document_cache: option.Option(document_cache.DocumentCache),
  )
}

Constructors

Events emitted during GraphQL execution for telemetry/instrumentation. These are emitted by the executor and passed to the telemetry_fn if one is configured.

pub type SchemaEvent {
  SchemaParseStart
  SchemaParseEnd(success: Bool, duration_ns: Int)
  SchemaValidationStart
  SchemaValidationEnd(
    success: Bool,
    error_count: Int,
    duration_ns: Int,
  )
  SchemaFieldStart(
    field_name: String,
    parent_type: String,
    path: List(String),
  )
  SchemaFieldEnd(
    field_name: String,
    parent_type: String,
    path: List(String),
    success: Bool,
    duration_ns: Int,
  )
  SchemaOperationStart(operation_name: option.Option(String))
  SchemaOperationEnd(
    operation_name: option.Option(String),
    success: Bool,
    error_count: Int,
  )
  SchemaDataLoaderBatch(
    loader_name: String,
    batch_size: Int,
    duration_ns: Int,
  )
}

Constructors

  • SchemaParseStart

    Query parsing is about to start.

  • SchemaParseEnd(success: Bool, duration_ns: Int)

    Query parsing has completed.

  • SchemaValidationStart

    Query validation is about to start.

  • SchemaValidationEnd(
      success: Bool,
      error_count: Int,
      duration_ns: Int,
    )

    Query validation has completed.

  • SchemaFieldStart(
      field_name: String,
      parent_type: String,
      path: List(String),
    )

    A field resolver is about to be called.

  • SchemaFieldEnd(
      field_name: String,
      parent_type: String,
      path: List(String),
      success: Bool,
      duration_ns: Int,
    )

    A field resolver has completed.

  • SchemaOperationStart(operation_name: option.Option(String))

    A GraphQL operation is about to be executed.

  • SchemaOperationEnd(
      operation_name: option.Option(String),
      success: Bool,
      error_count: Int,
    )

    A GraphQL operation has completed.

  • SchemaDataLoaderBatch(
      loader_name: String,
      batch_size: Int,
      duration_ns: Int,
    )

    DataLoader batch was executed.

Opaque type for telemetry context (defined in mochi/telemetry.gleam)

pub type TelemetryContext

Callback for receiving schema execution events. Wire this up to a telemetry handler (e.g. via telemetry.to_schema_fn/1).

pub type TelemetryFn =
  fn(SchemaEvent) -> Nil
pub type TypeDefinition {
  ObjectTypeDef(object_type: ObjectType)
  ScalarTypeDef(scalar_type: ScalarType)
  EnumTypeDef(enum_type: EnumType)
  InterfaceTypeDef(interface_type: InterfaceType)
  UnionTypeDef(union_type: UnionType)
  InputObjectTypeDef(input_object_type: InputObjectType)
}

Constructors

Type resolver function that determines the concrete type at runtime

pub type TypeResolver =
  fn(dynamic.Dynamic) -> Result(String, String)
pub type UnionType {
  UnionType(
    name: String,
    description: option.Option(String),
    types: List(ObjectType),
    resolve_type: option.Option(
      fn(dynamic.Dynamic) -> Result(String, String),
    ),
  )
}

Constructors

Opaque holder for user-provided execution context data.

Resolvers expect a specific user context type — the one their app configured. Exposing the raw Dynamic in ExecutionContext lied about that: it advertised “any data here” when in fact the system requires the app’s chosen type. UserContext keeps the runtime erasure (necessary because the executor doesn’t know the app’s type) but stops the lie at the type level.

Use user_context to wrap a value, and either context_accessor for typed reads, or read_user_context for one-off reads.

pub opaque type UserContext

Values

pub fn add_directive(
  schema: Schema,
  directive: DirectiveDefinition,
) -> Schema

Add a directive definition to the schema

pub fn add_type(
  schema: Schema,
  type_def: TypeDefinition,
) -> Schema
pub fn all_guards(
  guard_fns: List(fn(ResolverInfo) -> Result(Nil, String)),
) -> fn(ResolverInfo) -> Result(Nil, String)

Combine guards with AND logic — all must pass (checked in list order). Returns a single guard that fails with the first error encountered.

pub fn any_guard(
  guard_fns: List(fn(ResolverInfo) -> Result(Nil, String)),
) -> fn(ResolverInfo) -> Result(Nil, String)

Combine guards with OR logic — at least one must pass. Returns a single guard that succeeds if any guard passes, or fails with the last error if all fail.

pub fn arg(
  name: String,
  arg_type: FieldType,
) -> ArgumentDefinition
pub fn arg_description(
  arg: ArgumentDefinition,
  desc: String,
) -> ArgumentDefinition
pub fn argument(
  field: FieldDefinition,
  arg_def: ArgumentDefinition,
) -> FieldDefinition
pub fn auto_field(
  obj: ObjectType,
  name: String,
  field_type: FieldType,
) -> ObjectType

Add a field with auto-resolver (extracts field by name from parent)

pub fn auto_resolver(
  field_name: String,
) -> fn(ResolverInfo) -> Result(dynamic.Dynamic, String)

Create a resolver that auto-extracts a field from parent by name

pub fn bool_field(obj: ObjectType, name: String) -> ObjectType

Add a nullable Boolean field with auto-resolver

pub fn boolean_scalar() -> ScalarType
pub fn boolean_type() -> FieldType
pub fn builtin_directives() -> List(DirectiveDefinition)

Get all built-in directives

pub fn context_accessor(
  decoder: decode.Decoder(a),
) -> fn(ExecutionContext) -> Result(a, String)

Create a typed accessor for user_context. Define once per app, use in every resolver.

// context.gleam
pub const get_user_id = schema.context_accessor(decode.optional(decode.string))

// resolver
let auth = ctx |> context.get_user_id |> require_auth
use uid <- result.try(auth)
pub fn date_type() -> FieldType
pub fn datetime_type() -> FieldType
pub fn deprecated(
  field: FieldDefinition,
  reason: String,
) -> FieldDefinition
pub fn deprecated_directive() -> DirectiveDefinition

@deprecated(reason: String) directive

pub fn deprecated_no_reason(
  field: FieldDefinition,
) -> FieldDefinition
pub fn description(obj: ObjectType, desc: String) -> ObjectType
pub fn directive(
  name: String,
  locations: List(DirectiveLocation),
) -> DirectiveDefinition

Create a new directive definition

pub fn directive_argument(
  dir: DirectiveDefinition,
  arg_def: ArgumentDefinition,
) -> DirectiveDefinition

Add an argument to a directive

pub fn directive_description(
  dir: DirectiveDefinition,
  desc: String,
) -> DirectiveDefinition

Add description to a directive

pub fn directive_handler(
  dir: DirectiveDefinition,
  handler: fn(dict.Dict(String, dynamic.Dynamic), dynamic.Dynamic) -> Result(
    dynamic.Dynamic,
    String,
  ),
) -> DirectiveDefinition

Set the handler function for a directive (for field-level directives)

pub fn directive_location_to_string(
  loc: DirectiveLocation,
) -> String

Convert DirectiveLocation to string (for SDL generation)

pub fn directive_repeatable(
  dir: DirectiveDefinition,
) -> DirectiveDefinition

Make a directive repeatable

pub fn email_type() -> FieldType
pub fn execution_context(
  user_context user_context_value: a,
) -> ExecutionContext

Create a new execution context. The user_context value can be any app-defined type; it is wrapped opaquely and surfaced to resolvers via context_accessor / read_user_context.

pub fn field(
  obj: ObjectType,
  field_def: FieldDefinition,
) -> ObjectType
pub fn field_def(
  name: String,
  field_type: FieldType,
) -> FieldDefinition
pub fn field_description(
  field: FieldDefinition,
  desc: String,
) -> FieldDefinition
pub fn float_field(obj: ObjectType, name: String) -> ObjectType

Add a nullable Float field with auto-resolver

pub fn float_scalar() -> ScalarType
pub fn float_type() -> FieldType
pub fn get_data_loader(
  context: ExecutionContext,
  name: String,
) -> Result(
  dataloader.DataLoader(dynamic.Dynamic, dynamic.Dynamic),
  String,
)

Get a DataLoader from the execution context

pub fn get_middleware(
  context: ExecutionContext,
) -> option.Option(
  fn(
    String,
    FieldDefinition,
    ResolverInfo,
    fn(ResolverInfo) -> Result(dynamic.Dynamic, String),
  ) -> Result(dynamic.Dynamic, String),
)

Get the middleware function from context

pub fn get_telemetry(
  context: ExecutionContext,
) -> option.Option(TelemetryContext)

Get the telemetry context

pub fn get_telemetry_fn(
  context: ExecutionContext,
) -> option.Option(fn(SchemaEvent) -> Nil)

Get the telemetry callback function from the execution context

pub fn guard(
  field: FieldDefinition,
  guard_fn: fn(ResolverInfo) -> Result(Nil, String),
) -> FieldDefinition

Add a guard to a field definition. The guard runs before the resolver — if it returns Error, the resolver is skipped. Multiple guards can be stacked by calling this function multiple times; each new guard wraps the previous resolver+guards, so all must pass.

pub fn guards(
  field: FieldDefinition,
  guard_fns: List(fn(ResolverInfo) -> Result(Nil, String)),
) -> FieldDefinition

Add multiple guards to a field definition. Guards are checked in list order — the first guard in the list is checked first.

schema.field_def("secret", schema.string_type())
  |> schema.resolver(my_resolver)
  |> schema.guards([require_auth, require_admin])
  // require_auth is checked first, then require_admin
pub fn id_field(obj: ObjectType, name: String) -> ObjectType

Add a non-null ID field with auto-resolver

pub fn id_scalar() -> ScalarType
pub fn id_type() -> FieldType
pub fn implements(
  obj: ObjectType,
  interface: InterfaceType,
) -> ObjectType
pub fn include_directive() -> DirectiveDefinition

@include(if: Boolean!) directive

pub fn int_field(obj: ObjectType, name: String) -> ObjectType

Add a nullable Int field with auto-resolver

pub fn int_scalar() -> ScalarType
pub fn int_type() -> FieldType
pub fn interface(name: String) -> InterfaceType
pub fn interface_description(
  iface: InterfaceType,
  desc: String,
) -> InterfaceType
pub fn interface_field(
  iface: InterfaceType,
  field_def: FieldDefinition,
) -> InterfaceType
pub fn interface_resolve_type(
  iface: InterfaceType,
  resolver: fn(dynamic.Dynamic) -> Result(String, String),
) -> InterfaceType
pub fn json_type() -> FieldType
pub fn list_field(
  obj: ObjectType,
  name: String,
  item_type: String,
) -> ObjectType

Add a list field with auto-resolver

pub fn list_query(
  obj: ObjectType,
  name: String,
  item_type: String,
  desc: String,
  resolve_fn: fn(ResolverInfo) -> Result(dynamic.Dynamic, String),
) -> ObjectType

Add a list query field: name: [ItemType]

pub fn list_type(inner: FieldType) -> FieldType
pub fn load(
  context: ExecutionContext,
  loader_name: String,
  key: dynamic.Dynamic,
) -> #(ExecutionContext, Result(dynamic.Dynamic, String))

Load a value using a named DataLoader, returning updated context and result

This handles the context threading automatically.

Example

let #(ctx, result) = schema.load(ctx, "pokemon", dataloader.int_key(25))
pub fn load_by_id(
  context: ExecutionContext,
  loader_name: String,
  id: Int,
) -> #(ExecutionContext, Result(dynamic.Dynamic, String))

Load an entity by Int ID using a named DataLoader

Convenience wrapper for the common case of loading by integer ID.

Example

let #(ctx, pokemon) = schema.load_by_id(ctx, "pokemon", 25)
pub fn load_many(
  context: ExecutionContext,
  loader_name: String,
  keys: List(dynamic.Dynamic),
) -> #(ExecutionContext, List(Result(dynamic.Dynamic, String)))

Load multiple values using a named DataLoader

Example

let keys = list.map([1, 2, 3], dataloader.int_key)
let #(ctx, results) = schema.load_many(ctx, "pokemon", keys)
pub fn load_many_by_id(
  context: ExecutionContext,
  loader_name: String,
  ids: List(Int),
) -> #(ExecutionContext, List(Result(dynamic.Dynamic, String)))

Load multiple entities by Int IDs using a named DataLoader

Example

let #(ctx, pokemon_list) = schema.load_many_by_id(ctx, "pokemon", [1, 4, 7, 25])
pub fn mutation(
  schema: Schema,
  mutation_type: ObjectType,
) -> Schema
pub fn named_type(name: String) -> FieldType
pub fn non_null(inner: FieldType) -> FieldType
pub fn object(name: String) -> ObjectType
pub fn parse_literal(
  scalar: ScalarType,
  parse_fn: fn(dynamic.Dynamic) -> Result(dynamic.Dynamic, String),
) -> ScalarType
pub fn parse_value(
  scalar: ScalarType,
  parse_fn: fn(dynamic.Dynamic) -> Result(dynamic.Dynamic, String),
) -> ScalarType
pub fn query(schema: Schema, query_type: ObjectType) -> Schema
pub fn query_with_args(
  obj: ObjectType,
  name: String,
  field_type: FieldType,
  args: List(ArgumentDefinition),
  desc: String,
  resolve_fn: fn(ResolverInfo) -> Result(dynamic.Dynamic, String),
) -> ObjectType

Add a query field with arguments

pub fn read_user_context(
  uc: UserContext,
  decoder: decode.Decoder(a),
) -> Result(a, String)

Read the wrapped value back, decoding into an app-defined type.

pub fn ref_field(
  obj: ObjectType,
  name: String,
  type_name: String,
) -> ObjectType

Add a reference field to another type with auto-resolver

pub fn ref_query(
  obj: ObjectType,
  name: String,
  type_name: String,
  desc: String,
  resolve_fn: fn(ResolverInfo) -> Result(dynamic.Dynamic, String),
) -> ObjectType

Add a reference query field: name: TypeName

pub fn required_bool_field(
  obj: ObjectType,
  name: String,
) -> ObjectType

Add a non-null Boolean field with auto-resolver

pub fn required_float_field(
  obj: ObjectType,
  name: String,
) -> ObjectType

Add a non-null Float field with auto-resolver

pub fn required_int_field(
  obj: ObjectType,
  name: String,
) -> ObjectType

Add a non-null Int field with auto-resolver

pub fn required_list_field(
  obj: ObjectType,
  name: String,
  item_type: String,
) -> ObjectType

Add a non-null list field with auto-resolver

pub fn required_ref_field(
  obj: ObjectType,
  name: String,
  type_name: String,
) -> ObjectType

Add a non-null reference field with auto-resolver

pub fn required_string_field(
  obj: ObjectType,
  name: String,
) -> ObjectType

Add a non-null String field with auto-resolver

pub fn resolver(
  field: FieldDefinition,
  resolve_fn: fn(ResolverInfo) -> Result(dynamic.Dynamic, String),
) -> FieldDefinition
pub fn resolver_field(
  obj: ObjectType,
  name: String,
  field_type: FieldType,
  desc: String,
  resolve_fn: fn(ResolverInfo) -> Result(dynamic.Dynamic, String),
) -> ObjectType

Add a field with custom resolver and optional description

pub fn rich_resolver_fn(
  field: FieldDefinition,
  resolve_fn: fn(ResolverInfo) -> Result(
    dynamic.Dynamic,
    #(String, option.Option(dict.Dict(String, dynamic.Dynamic))),
  ),
) -> FieldDefinition
pub fn scalar(name: String) -> ScalarType
pub fn scalar_description(
  scalar: ScalarType,
  desc: String,
) -> ScalarType
pub fn schema() -> Schema
pub fn serialize(
  scalar: ScalarType,
  serialize_fn: fn(dynamic.Dynamic) -> Result(
    dynamic.Dynamic,
    String,
  ),
) -> ScalarType
pub fn skip_directive() -> DirectiveDefinition

@skip(if: Boolean!) directive

pub fn string_field(obj: ObjectType, name: String) -> ObjectType

Add a nullable String field with auto-resolver

pub fn string_scalar() -> ScalarType
pub fn string_type() -> FieldType
pub fn subscription(
  schema: Schema,
  subscription_type: ObjectType,
) -> Schema
pub fn union(name: String) -> UnionType
pub fn union_description(
  union_type: UnionType,
  desc: String,
) -> UnionType
pub fn union_member(
  union_type: UnionType,
  member: ObjectType,
) -> UnionType
pub fn union_resolve_type(
  union_type: UnionType,
  resolver: fn(dynamic.Dynamic) -> Result(String, String),
) -> UnionType
pub fn update_data_loader(
  context: ExecutionContext,
  name: String,
  loader: dataloader.DataLoader(dynamic.Dynamic, dynamic.Dynamic),
) -> ExecutionContext

Update a DataLoader in the execution context

pub fn update_telemetry(
  context: ExecutionContext,
  telemetry: TelemetryContext,
) -> ExecutionContext

Update the telemetry context

pub fn url_type() -> FieldType
pub fn user_context(value: a) -> UserContext

Wrap an app-defined value so it can be carried through the executor.

pub fn uuid_type() -> FieldType
pub fn with_loaders(
  context: ExecutionContext,
  loaders: List(
    #(
      String,
      dataloader.DataLoader(dynamic.Dynamic, dynamic.Dynamic),
    ),
  ),
) -> ExecutionContext

Add multiple DataLoaders to the execution context at once

Example

let ctx = schema.execution_context(user_ctx)
  |> schema.with_loaders([
    #("pokemon", pokemon_loader),
    #("move", move_loader),
    #("trainer", trainer_loader),
  ])
pub fn with_middleware(
  context: ExecutionContext,
  middleware: fn(
    String,
    FieldDefinition,
    ResolverInfo,
    fn(ResolverInfo) -> Result(dynamic.Dynamic, String),
  ) -> Result(dynamic.Dynamic, String),
) -> ExecutionContext

Set middleware function on an execution context

pub fn with_telemetry(
  context: ExecutionContext,
  telemetry: TelemetryContext,
) -> ExecutionContext

Set telemetry on an execution context

pub fn with_telemetry_fn(
  context: ExecutionContext,
  telemetry_fn: fn(SchemaEvent) -> Nil,
) -> ExecutionContext

Set a telemetry callback function on the execution context. This function is called for each SchemaEvent emitted during execution. Use telemetry.to_schema_fn/1 to bridge a TelemetryConfig to this callback.

Search Document