make_operation!() { /* proc-macro */ }Expand description
Generates the Operation enum and its dispatch logic from a GraphQL schema file.
§Usage
make_operation!("path/to/schema.graphql");
// or with options:
make_operation!(
"path/to/schema.graphql",
type_module = crate::types, // module path to types from make_types!
type_override = Query.operation: CustomType, // override an operation return type
type_override = Query.operation.arg: CustomType, // override an operation argument type
name_override = TypeName: NewTypeName, // rename a type (must match make_types!)
error_logging = false, // disable error logging (feature: log)
);This is one of three composable macros that together replace [appsync_lambda_main!]:
- make_types! — generates Rust types (structs and enums) from the schema
make_operation!— generates theOperationenum, sub-enums (QueryField,MutationField,SubscriptionField), argument extraction, default operation implementations, and theexecutedispatch method- make_handlers! — generates the Lambda handler and runtime setup
make_appsync! is a convenience macro that combines all three.
§Schema Path Argument
The first argument to this macro must be a string literal containing the path to your GraphQL schema file. The schema path can be:
- An absolute filesystem path (e.g. “/home/user/project/schema.graphql”)
- A relative path, that will be relative to your crate’s root directory (e.g. “schema.graphql”, “graphql/schema.gql”)
- When in a workspace context, the relative path will be relative to the workspace root directory
§Important Prerequisite
The types referenced by operations (return types, argument types) must be in scope when
make_operation! is invoked. There are two ways to achieve this:
- Same scope: Call make_types! (or make_appsync!) in the same scope before
make_operation! - Different module/crate: Use the
type_moduleparameter to specify the path to the module containing the types generated by make_types!
§Options
type_module = path::to::types: Prefix all custom type references with the given module path- (feature:
log)error_logging = bool: Log errors vialog::error!before converting them to anAppsyncResponse(default:true) type_override— see section below for detailsname_override— see section below for details
§Type Overrides
The type_override option allows overriding Rust types for operation return types and argument
types:
- Operation return types (Query/Mutation):
type_override = OpType.operation: CustomType - Operation arguments (Query/Mutation/Subscription):
type_override = OpType.operation.arg: CustomType
These overrides are only for the Rust code and must be compatible for serialization/deserialization
purposes, i.e. you can use String for a GraphQL ID but you cannot use a u32 for a GraphQL
Float.
§Name Overrides
The name_override option supports renaming various schema elements:
- Type/input/enum names:
name_override = TypeName: NewTypeName - Field names:
name_override = Type.field: new_field_name - Enum variants:
name_override = Enum.VARIANT: NewVariant
When using make_operation! separately from make_types!, you must repeat the same
name_override entries so that operation signatures reference the correct renamed types.
§type_module
Specifies the module path where the GraphQL types (generated by make_types!) are located. When set, all custom type references in operation signatures will be prefixed with this path.
This is the alternative to bringing all types into scope with use types::*;.
§What Gets Generated
§Sub-enums for each operation kind
For each of Query, Mutation and Subscription defined in the schema, a field enum is generated:
#[derive(Debug, Clone, Copy, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum QueryField { Players, GameStatus, Player }
#[derive(Debug, Clone, Copy, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum MutationField { CreatePlayer, DeletePlayer, SetGameStatus }
#[derive(Debug, Clone, Copy, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum SubscriptionField { OnCreatePlayer, OnDeletePlayer, OnGameStatusChange }§The Operation enum
#[derive(Debug, Clone, Copy, Deserialize)]
#[serde(tag = "parentTypeName", content = "fieldName")]
pub enum Operation {
Query(QueryField),
Mutation(MutationField),
Subscription(SubscriptionField),
}§Default operation implementations
For each operation, a default async function is generated as a trait method:
- Queries and mutations return
Err(AppsyncError::new("Unimplemented", "..."))by default - Subscriptions return
Ok(None)by default (no filter)
These defaults are overridden when you use the appsync_operation attribute macro on your handler functions.
§The execute method
impl Operation {
async fn execute(self, event: AppsyncEvent<Self>) -> AppsyncResponse {
/* ... */
}
}This method dispatches to the appropriate operation handler, serializes the result, and (if
error_logging is enabled) logs errors via log::error!.
§Examples
§Basic usage (types in same scope)
use lambda_appsync::{make_types, make_operation};
// Generate types first
make_types!("schema.graphql");
// Then generate operations (types are in scope)
make_operation!("schema.graphql");§Using type_module for cross-module types
use lambda_appsync::make_operation;
// Types are in a separate module
make_operation!(
"schema.graphql",
type_module = crate::types,
);§Override operation return types and argument types
use lambda_appsync::{make_types, make_operation};
make_types!(
"schema.graphql",
type_override = Player.id: String,
);
make_operation!(
"schema.graphql",
// Override argument types to match the type overrides
type_override = Query.player.id: String,
type_override = Mutation.deletePlayer.id: String,
type_override = Subscription.onDeletePlayer.id: String,
);§Disable error logging
use lambda_appsync::{make_types, make_operation};
make_types!("schema.graphql");
make_operation!(
"schema.graphql",
error_logging = false,
);§With name overrides
use lambda_appsync::{make_types, make_operation};
make_types!(
"schema.graphql",
name_override = Player: NewPlayer,
);
// MUST repeat the same name_override entries
make_operation!(
"schema.graphql",
name_override = Player: NewPlayer,
// MUST also override the operations return type
type_override = Query.players: NewPlayer,
type_override = Query.player: NewPlayer,
type_override = Mutation.createPlayer: NewPlayer,
type_override = Mutation.deletePlayer: NewPlayer,
);§Important
- This macro requires that the GraphQL types (structs and enums) are already in scope, either via
make_types! in the same scope or via
type_module. - The appsync_operation attribute macro depends on being able to add impl Operation {…}
blocks. You must use
make_operation!(or make_appsync!) in a parent module in order to use#[appsync_operation(...)]. - When using
type_overrideorname_override, ensure consistency between make_types! andmake_operation!invocations — mismatched overrides will cause compilation errors.