mochi/middleware
Types
Filter to determine which fields a middleware applies to
pub type FieldFilter {
SpecificFields(List(#(String, String)))
TypeFields(List(String))
NamedFields(List(String))
AllFields
}
Constructors
-
SpecificFields(List(#(String, String)))Apply to specific (type, field) pairs
-
TypeFields(List(String))Apply to all fields on specific types
-
NamedFields(List(String))Apply to fields with specific names (on any type)
-
AllFieldsApply to all fields
Middleware function type Takes the current resolution state and a “next” function to continue the chain
pub type Middleware =
fn(Resolution, fn(Resolution) -> Resolution) -> Resolution
A middleware definition with metadata
pub type MiddlewareDef {
MiddlewareDef(
name: String,
priority: Int,
field_filter: option.Option(FieldFilter),
middleware: fn(Resolution, fn(Resolution) -> Resolution) -> Resolution,
)
}
Constructors
-
MiddlewareDef( name: String, priority: Int, field_filter: option.Option(FieldFilter), middleware: fn(Resolution, fn(Resolution) -> Resolution) -> Resolution, )Arguments
- name
-
Name for debugging/logging
- priority
-
Priority - lower values run first (default: 100)
- field_filter
-
Optional filter to only apply to certain fields
- middleware
-
The middleware function
The middleware pipeline containing all registered middleware
pub opaque type MiddlewarePipeline
Resolution state passed through the middleware chain
pub type Resolution {
Resolution(
value: option.Option(dynamic.Dynamic),
error: option.Option(String),
field_name: String,
parent_type: String,
context: ResolverContext,
private: dict.Dict(String, dynamic.Dynamic),
)
}
Constructors
-
Resolution( value: option.Option(dynamic.Dynamic), error: option.Option(String), field_name: String, parent_type: String, context: ResolverContext, private: dict.Dict(String, dynamic.Dynamic), )Arguments
- value
-
The resolved value (None if not yet resolved or if error occurred)
- error
-
Error message if resolution failed
- field_name
-
Field name being resolved
- parent_type
-
Parent type name
- context
-
Resolver context
- private
-
Private data that middleware can use to communicate
Information about the current field being resolved
pub type ResolverContext {
ResolverContext(
field_name: String,
parent_type: String,
path: List(String),
info: schema.ResolverInfo,
)
}
Constructors
-
ResolverContext( field_name: String, parent_type: String, path: List(String), info: schema.ResolverInfo, )Arguments
- field_name
-
The field name being resolved
- parent_type
-
The parent type name
- path
-
Current path in the query
- info
-
The full resolver info
Values
pub fn add_middleware(
pipeline: MiddlewarePipeline,
mw: MiddlewareDef,
) -> MiddlewarePipeline
Add middleware to the pipeline
pub fn auth_middleware(
role_extractor: fn(schema.UserContext) -> option.Option(String),
required_role: String,
) -> MiddlewareDef
Authorization middleware that checks for a specific role in context.
role_extractor receives a decoder-friendly view of the user context.
The middleware decodes via the supplied decoder, then asks the
extractor for the role string.
pub fn caching_middleware(
cache_key: fn(Resolution) -> String,
get_cached: fn(String) -> option.Option(dynamic.Dynamic),
set_cached: fn(String, dynamic.Dynamic) -> Nil,
) -> MiddlewareDef
Caching middleware that caches field results
pub fn error_wrapper_middleware(
wrapper: fn(String) -> String,
) -> MiddlewareDef
Error wrapping middleware that transforms errors
pub fn execute_with_middleware(
pipeline: MiddlewarePipeline,
parent_type: String,
field_def: schema.FieldDefinition,
info: schema.ResolverInfo,
resolver: fn(schema.ResolverInfo) -> Result(
dynamic.Dynamic,
String,
),
) -> Result(dynamic.Dynamic, String)
Execute a resolver with the middleware pipeline
pub fn get_private(
resolution: Resolution,
key: String,
) -> option.Option(dynamic.Dynamic)
Get private data from the resolution
pub fn logging_middleware(
log_fn: fn(String) -> Nil,
) -> MiddlewareDef
Logging middleware that logs field resolution
pub fn middleware(
name: String,
mw_fn: fn(Resolution, fn(Resolution) -> Resolution) -> Resolution,
) -> MiddlewareDef
Create a basic middleware definition
pub fn new_resolution(
field_name: String,
parent_type: String,
context: ResolverContext,
) -> Resolution
Create a new resolution state for a field
pub fn put_private(
resolution: Resolution,
key: String,
value: dynamic.Dynamic,
) -> Resolution
Add private data to the resolution
pub fn rate_limit_middleware(
key_extractor: fn(Resolution) -> String,
max_requests: Int,
checker: fn(String, Int) -> Bool,
) -> MiddlewareDef
Rate limiting middleware (simple in-memory version) Note: For production, use external state (Redis, etc.)
pub fn set_error(
resolution: Resolution,
error: String,
) -> Resolution
Set an error on the resolution
pub fn set_value(
resolution: Resolution,
value: dynamic.Dynamic,
) -> Resolution
Set the resolved value
pub fn timing_middleware(
get_time: fn() -> Int,
record_timing: fn(String, String, Int) -> Nil,
) -> MiddlewareDef
Timing middleware that records field resolution time
pub fn to_executor_fn(
pipeline: MiddlewarePipeline,
) -> fn(
String,
schema.FieldDefinition,
schema.ResolverInfo,
fn(schema.ResolverInfo) -> Result(dynamic.Dynamic, String),
) -> Result(dynamic.Dynamic, String)
Convert a MiddlewarePipeline to a schema.MiddlewareFn
This is used to wire a middleware pipeline into the execution context without creating a circular dependency between schema and middleware.
Example
let pipeline = middleware.new_pipeline()
|> middleware.add_middleware(middleware.logging_middleware(io.println))
let ctx = schema.execution_context(user_ctx)
|> schema.with_middleware(middleware.to_executor_fn(pipeline))
pub fn transform_middleware(
transform: fn(dynamic.Dynamic) -> dynamic.Dynamic,
) -> MiddlewareDef
Transform middleware that transforms the resolved value
pub fn validation_middleware(
validator: fn(schema.ResolverInfo) -> Result(Nil, String),
) -> MiddlewareDef
Validation middleware that validates arguments
pub fn with_filter(
mw: MiddlewareDef,
filter: FieldFilter,
) -> MiddlewareDef
Set a field filter on middleware
pub fn with_priority(
mw: MiddlewareDef,
priority: Int,
) -> MiddlewareDef
Set the priority of a middleware (lower runs first)