-
Notifications
You must be signed in to change notification settings - Fork 161
Open
Labels
confirmedThe scope is clear, ready for implementationThe scope is clear, ready for implementationevent-handlerThis item relates to the Event Handler UtilityThis item relates to the Event Handler Utilityfeature-requestThis item refers to a feature request for an existing or new utilityThis item refers to a feature request for an existing or new utilityhelp-wantedWe would really appreciate some support from community for this oneWe would really appreciate some support from community for this one
Description
Use case
The TypeScript version of Powertools already has a Router
class for organizing GraphQL resolvers, but it's missing a functionality that exists in the Python version:
- Router Composition: The ability to include multiple
Router
instances in the mainAppSyncGraphQLResolver
using anincludeRouter()
method - Context Sharing: The ability to share contextual data between the main resolver and included routers using
appendContext()
Currently, developers can create Router
instances but cannot easily compose them into a main resolver, limiting the modularity benefits. The Python version already has this functionality through include_router()
and append_context()
methods.
Solution/User Experience
Add the missing router composition and context sharing functionality to match the Python implementation:
includeRouter()
method: AllowAppSyncGraphQLResolver
to include multipleRouter
instancesappendContext()
method: Enable sharing data between main resolver and routers- Context access: Allow routers to access shared context data in their handlers
Example Usage:
// userRoutes.ts
import { Router } from '@aws-lambda-powertools/event-handler/appsync-graphql';
const userRouter = new Router();
userRouter.onQuery<{ id: string }>('getUser', async ({ id }, { context }) => {
// Access shared context
const isAdmin = context?.get('isAdmin', false);
return {
id,
name: 'John Doe',
email: isAdmin ? '[email protected]' : 'hidden'
};
});
userRouter.onMutation<{ name: string; email: string }>('createUser', async ({ name, email }) => {
return { id: makeId(), name, email };
});
export { userRouter };
// todoRoutes.ts
import { Router } from '@aws-lambda-powertools/event-handler/appsync-graphql';
const todoRouter = new Router();
todoRouter.onQuery<{ id: string }>('getTodo', async ({ id }, { context }) => {
const requestId = context?.get('requestId');
logger.info('Fetching todo', { id, requestId });
return { id, title: 'Sample Todo', completed: false };
});
export { todoRouter };
// index.ts - Main Lambda handler
import { AppSyncGraphQLResolver } from '@aws-lambda-powertools/event-handler/appsync-graphql';
import { Logger } from '@aws-lambda-powertools/logger';
import type { Context } from 'aws-lambda';
import { userRouter } from './userRoutes.js';
import { todoRouter } from './todoRoutes.js';
const logger = new Logger({ serviceName: 'GraphQLAPI' });
const app = new AppSyncGraphQLResolver({ logger });
// Include routers - NEW FUNCTIONALITY
app.includeRouter(userRouter);
app.includeRouter(todoRouter);
export const handler = async (event: unknown, context: Context) => {
// Share context between main app and routers - NEW FUNCTIONALITY
app.appendContext({
isAdmin: true,
requestId: context.awsRequestId,
timestamp: Date.now()
});
return app.resolve(event, context);
};
Implementation Details:
- Router Registry Merging: The
includeRouter()
method should merge the router's resolver registry with the main resolver's registry - Context Management:
- Add a context storage mechanism (Map or similar) to store key-value pairs
- Context should be accessible in resolver handlers via the options parameter
- Context should be cleared after each invocation for safety
- Type Safety: Ensure proper TypeScript types for context methods and router inclusion
Expected API:
class AppSyncGraphQLResolver extends Router {
// NEW: Include a router instance
public includeRouter(router: Router): void;
// NEW: Add context data to be shared with routers
public appendContext(data: Record<string, unknown>): void;
// NEW: Access to context (internal)
public readonly context: Map<string, unknown>;
}
// Updated resolver handler signature to include context access
type ResolverHandler<TParams = Record<string, unknown>> = (
args: TParams,
options: {
event: AppSyncResolverEvent<TParams>;
context: Context;
// NEW: Shared context access
context?: Map<string, unknown>;
}
) => Promise<unknown> | unknown;
Alternative solutions
- Manual Registry Merging: Developers could manually access the router's registry and merge it, but this exposes internal implementation details
- Inheritance Pattern: Create a base class that both Router and AppSyncGraphQLResolver extend, but this changes the current architecture
- Composition via Constructor: Pass routers during AppSyncGraphQLResolver construction, but this is less flexible than the include pattern
Benefits:
- Consistency: Matches the Python implementation's API
- Modularity: Enables better code organization across multiple files/modules
- Context Sharing: Allows passing request-scoped data between resolvers
- Backward Compatibility: Doesn't break existing Router or AppSyncGraphQLResolver usage
Acknowledgment
- This feature request meets Powertools for AWS Lambda (TypeScript) Tenets
- Should this be considered in other Powertools for AWS Lambda languages? i.e. Python, Java, and .NET
Future readers
Please react with 👍 and your use case to help us understand customer demand.
Metadata
Metadata
Assignees
Labels
confirmedThe scope is clear, ready for implementationThe scope is clear, ready for implementationevent-handlerThis item relates to the Event Handler UtilityThis item relates to the Event Handler Utilityfeature-requestThis item refers to a feature request for an existing or new utilityThis item refers to a feature request for an existing or new utilityhelp-wantedWe would really appreciate some support from community for this oneWe would really appreciate some support from community for this one
Type
Projects
Status
Backlog