Skip to main content

Crate lambda_appsync

Crate lambda_appsync 

Source
Expand description

A type-safe framework for AWS AppSync Direct Lambda resolvers.

This crate provides procedural macros and types for implementing AWS AppSync Direct Lambda resolvers. It converts GraphQL schemas into type-safe Rust code with full AWS Lambda runtime support.

The recommended entry point is make_appsync!, a convenience macro that generates all necessary types, the Operation dispatch enum, and a Handlers trait from a .graphql schema file. For finer control (e.g. shared-types libraries or multi-Lambda setups), the three composable macros make_types!, make_operation!, and make_handlers! can be used individually. Resolver functions are annotated with appsync_operation.

§Key Concepts

§Macros

§All-in-one

  • make_appsync! — reads a GraphQL schema file at compile time and generates:

    • Rust types for all GraphQL objects/enums/inputs,
    • an Operation enum covering every query/mutation/subscription field, and
    • a Handlers trait with a DefaultHandlers struct for wiring up the Lambda runtime.

    This is the recommended macro for single-crate projects.

§Composable

  • make_types! — generates Rust structs and enums from the schema’s type, input, and enum definitions.
  • make_operation! — generates the Operation enum, sub-enums (QueryField, MutationField, SubscriptionField), argument extraction, and the execute dispatch method. Requires the types from make_types! to be in scope.
  • make_handlers! — generates the Handlers trait and DefaultHandlers struct for the Lambda runtime. Requires the Operation type from make_operation! to be in scope.

§Resolver attribute

  • appsync_operation — attribute macro applied to async resolver functions. It validates that the function signature matches the corresponding GraphQL field and registers the function as the handler for that operation.

§Deprecated

  • appsync_lambda_main! (compat feature) — the legacy monolithic macro. It combines type generation, operation dispatch, Lambda runtime setup, and AWS SDK client initialization into one call. Prefer make_appsync! or the composable macros for new code.

§Event and Response Types

Every Lambda invocation receives an AppsyncEvent<O> where O is the generated Operation enum. The event carries:

Resolver functions return Result<T, AppsyncError>. The framework serializes responses and wraps them in an AppsyncResponse.

§Identity and Authorization

AppsyncIdentity is an enum with one variant per AppSync authorization mode:

VariantAuth modeDetail struct
AppsyncIdentity::CognitoCognito User PoolsAppsyncIdentityCognito
AppsyncIdentity::IamAWS IAM / Cognito Identity PoolsAppsyncIdentityIam
AppsyncIdentity::OidcOpenID ConnectAppsyncIdentityOidc
AppsyncIdentity::LambdaLambda authorizerAppsyncIdentityLambda
AppsyncIdentity::ApiKeyAPI Key(no extra data)

§AWS AppSync Scalar Types

The crate provides Rust types for all AppSync-specific GraphQL scalars:

§Subscription Filters

The subscription_filters module provides a type-safe builder for AppSync enhanced subscription filters. Filters are constructed from subscription_filters::FieldPath operator methods, combined into subscription_filters::Filter (AND logic, up to 5 conditions) and subscription_filters::FilterGroup (OR logic, up to 10 filters). AWS AppSync’s size constraints are enforced at compile time.

§Error Handling

AppsyncError carries an error_type and error_message. Multiple errors can be merged with the | operator, which concatenates both fields. Any AWS SDK error that implements ProvideErrorMetadata converts into an AppsyncError via ?.

§Tracing Integration

When the tracing feature is enabled, the generated Handlers trait automatically wraps each event dispatch in a tracing::info_span!("AppsyncEvent", ...) that records the operation being executed (and the batch index, when batch mode is active). This helps give you per-operation spans linked with the parent without writing any instrumentation boilerplate. The feature also re-exports tracing and tracing-subscriber for convenience.

§Complete Example

Given a GraphQL schema (schema.graphql):

type Query {
  players: [Player!]!
  gameStatus: GameStatus!
}

type Player {
  id: ID!
  name: String!
  team: Team!
}

enum Team {
  RUST
  PYTHON
  JS
}

enum GameStatus {
  STARTED
  STOPPED
}
use lambda_appsync::{make_appsync, appsync_operation, AppsyncError};

// Generate types, Operation enum, and Handlers trait from schema
make_appsync!("schema.graphql");

// Implement resolver functions for GraphQL operations:

#[appsync_operation(query(players))]
async fn get_players() -> Result<Vec<Player>, AppsyncError> {
    todo!()
}

#[appsync_operation(query(gameStatus))]
async fn get_game_status() -> Result<GameStatus, AppsyncError> {
    todo!()
}

// Wire up the Lambda runtime in main:

#[tokio::main]
async fn main() -> Result<(), lambda_runtime::Error> {
    lambda_runtime::run(
        lambda_runtime::service_fn(DefaultHandlers::service_fn)
    ).await
}

§Custom handler with authentication hook

Override the Handlers trait to add pre-processing logic (replaces the old hook parameter from appsync_lambda_main!):

use lambda_appsync::{make_appsync, appsync_operation, AppsyncError};
use lambda_appsync::{AppsyncEvent, AppsyncResponse, AppsyncIdentity};

make_appsync!("schema.graphql");

struct MyHandlers;
impl Handlers for MyHandlers {
    async fn appsync_handler(event: AppsyncEvent<Operation>) -> AppsyncResponse {
        // Custom authentication check
        if let AppsyncIdentity::ApiKey = &event.identity {
            return AppsyncResponse::unauthorized();
        }
        // Delegate to the default operation dispatch
        event.info.operation.execute(event).await
    }
}

#[appsync_operation(query(players))]
async fn get_players() -> Result<Vec<Player>, AppsyncError> {
    todo!()
}

#[appsync_operation(query(gameStatus))]
async fn get_game_status() -> Result<GameStatus, AppsyncError> {
    todo!()
}

#[tokio::main]
async fn main() -> Result<(), lambda_runtime::Error> {
    lambda_runtime::run(
        lambda_runtime::service_fn(MyHandlers::service_fn)
    ).await
}

§Using the composable macros

For multi-crate setups (e.g. a shared types library with separate Lambda binaries), use the individual macros:

use lambda_appsync::{make_types, make_operation, make_handlers, appsync_operation, AppsyncError};

// Step 1: Generate types (could live in a shared lib crate)
make_types!("schema.graphql");

// Step 2: Generate Operation enum and dispatch logic
make_operation!("schema.graphql");

// Step 3: Generate Handlers trait and DefaultHandlers
make_handlers!();

#[appsync_operation(query(players))]
async fn get_players() -> Result<Vec<Player>, AppsyncError> {
    todo!()
}

#[appsync_operation(query(gameStatus))]
async fn get_game_status() -> Result<GameStatus, AppsyncError> {
    todo!()
}

#[tokio::main]
async fn main() -> Result<(), lambda_runtime::Error> {
    lambda_runtime::run(
        lambda_runtime::service_fn(DefaultHandlers::service_fn)
    ).await
}

§Feature Flags

FeatureDescription
compatEnables the deprecated appsync_lambda_main! macro and re-exports aws_config, lambda_runtime, and tokio. Not required when using make_appsync! or the composable macros (you depend on lambda_runtime and tokio directly).
logRe-exports the log crate so resolver code can use log::info! etc. without a separate dependency.
env_loggerInitializes env_logger for local development. Implies log and compat.
tracingRe-exports tracing and tracing-subscriber for structured, async-aware logging.

Re-exports§

pub use lambda_runtime;
pub use serde;
pub use serde_json;
pub use tokio;

Modules§

subscription_filters
GraphQL subscription filter implementation for AWS AppSync

Macros§

make_appsync
Convenience macro that combines make_types!, make_operation!, and make_handlers! into a single invocation.
make_handlers
Generates a Handlers trait and a DefaultHandlers struct for handling AWS AppSync Lambda events.
make_operation
Generates the Operation enum and its dispatch logic from a GraphQL schema file.
make_types
Generates Rust types (structs and enums) from a GraphQL schema file.

Structs§

AWSDate
AWS AppSync specific GraphQL scalar type implemented a String new-type
AWSDateTime
AWS AppSync specific GraphQL scalar type implemented a String new-type
AWSEmail
AWS AppSync specific GraphQL scalar type implemented a String new-type
AWSPhone
AWS AppSync specific GraphQL scalar type implemented a String new-type
AWSTime
AWS AppSync specific GraphQL scalar type implemented a String new-type
AWSTimestamp
AWS AppSync specific GraphQL scalar type implemented SystemTime new-type. Note that this type implements Copy
AWSUrl
AWS AppSync specific GraphQL scalar type implemented a String new-type
AppsyncError
Error type for AWS AppSync operations
AppsyncEvent
Represents a complete AWS AppSync event sent to a Lambda resolver.
AppsyncEventInfo
Metadata about an AppSync GraphQL operation execution.
AppsyncIdentityCognito
Identity information for Cognito User Pools authenticated requests.
AppsyncIdentityIam
Identity information for IAM-authenticated requests.
AppsyncIdentityLambda
Identity information for Lambda-authorized requests.
AppsyncIdentityOidc
Identity information for OIDC-authenticated requests.
AppsyncResponse
Response structure returned to AWS AppSync from a Lambda resolver.
CognitoFederatedIdentity
Cognito Identity Pool information for federated IAM authentication
ID
A custom UUID-based identifier type for AppSync GraphQL objects.

Enums§

AppsyncAuthStrategy
Authorization strategy for AppSync operations.
AppsyncIdentity
Identity information for an AppSync request.
CognitoIdentityAuthType
Authentication type in a Cognito Identity Pool

Functions§

arg_from_json
Extracts and deserializes a named argument from a JSON Value into the specified type
res_to_json
Serializes a value into a JSON Value for AppSync responses

Attribute Macros§

appsync_operation
Marks an async function as an AWS AppSync resolver operation, binding it to a specific Query, Mutation or Subscription operation defined in the GraphQL schema.