@onivoro/server-aws-lambda
v24.33.9
Published
Type-safe AWS Lambda invocation for NestJS applications.
Downloads
457
Readme
@onivoro/server-aws-lambda
Type-safe AWS Lambda invocation for NestJS applications.
Installation
npm install @onivoro/server-aws-lambdaOverview
This library provides a simple AWS Lambda integration for NestJS applications, offering type-safe Lambda function invocation with automatic response parsing.
Module Setup
import { Module } from '@nestjs/common';
import { ServerAwsLambdaModule } from '@onivoro/server-aws-lambda';
@Module({
imports: [
ServerAwsLambdaModule.configure()
]
})
export class AppModule {}Configuration
The module uses environment-based configuration:
export class ServerAwsLambdaConfig {
AWS_REGION: string;
AWS_PROFILE?: string; // Optional AWS profile
}Service
LambdaService
The main service for invoking Lambda functions:
import { Injectable } from '@nestjs/common';
import { LambdaService } from '@onivoro/server-aws-lambda';
@Injectable()
export class FunctionInvokerService {
constructor(private readonly lambdaService: LambdaService) {}
async invokeDataProcessor(data: any) {
const result = await this.lambdaService.invoke<ProcessorResponse>({
functionName: 'data-processor-function',
body: {
action: 'process',
data: data
}
});
return result;
}
async invokeWithoutPayload(functionName: string) {
return await this.lambdaService.invoke({
functionName
});
}
}Method Details
invoke(params)
The invoke method accepts an object with the following properties:
- functionName (string, required): The name or ARN of the Lambda function
- body (any, optional): The payload to send to the function (will be JSON stringified)
The method returns the parsed response of type T (if specified).
Response Parsing
The service automatically handles response parsing with the following logic:
- If the Lambda returns a response with
statusCodeandbody(API Gateway format), it parses the nested body - Otherwise, it returns the Lambda response payload directly
- All responses are automatically JSON parsed
Type Safety
Use TypeScript generics for type-safe responses:
interface UserData {
id: string;
name: string;
email: string;
}
const userData = await lambdaService.invoke<UserData>({
functionName: 'get-user-function',
body: { userId: '123' }
});
// userData is typed as UserData
console.log(userData.email);Direct Client Access
The service exposes the underlying Lambda client for advanced operations:
import {
ListFunctionsCommand,
GetFunctionCommand,
UpdateFunctionCodeCommand,
CreateFunctionCommand
} from '@aws-sdk/client-lambda';
@Injectable()
export class AdvancedLambdaService {
constructor(private readonly lambdaService: LambdaService) {}
// List all Lambda functions
async listFunctions() {
const command = new ListFunctionsCommand({});
return await this.lambdaService.lambdaClient.send(command);
}
// Get function configuration
async getFunctionInfo(functionName: string) {
const command = new GetFunctionCommand({
FunctionName: functionName
});
return await this.lambdaService.lambdaClient.send(command);
}
// Invoke with specific invocation type
async invokeAsync(functionName: string, payload: any) {
const command = new InvokeCommand({
FunctionName: functionName,
InvocationType: 'Event', // Async invocation
Payload: Buffer.from(JSON.stringify(payload))
});
return await this.lambdaService.lambdaClient.send(command);
}
}Complete Example
import { Module, Injectable } from '@nestjs/common';
import { ServerAwsLambdaModule, LambdaService } from '@onivoro/server-aws-lambda';
// Types for Lambda responses
interface CalculationResult {
result: number;
operation: string;
timestamp: string;
}
interface ValidationResult {
isValid: boolean;
errors?: string[];
}
@Module({
imports: [ServerAwsLambdaModule.configure()],
providers: [MicroserviceGateway],
exports: [MicroserviceGateway]
})
export class GatewayModule {}
@Injectable()
export class MicroserviceGateway {
constructor(private readonly lambdaService: LambdaService) {}
// Invoke calculation microservice
async calculate(operation: string, values: number[]) {
try {
const result = await this.lambdaService.invoke<CalculationResult>({
functionName: 'calculator-service',
body: {
operation,
values
}
});
console.log(`Calculation completed: ${result.operation} = ${result.result}`);
return result;
} catch (error) {
console.error('Calculation failed:', error);
throw error;
}
}
// Invoke validation microservice
async validateData(data: any, rules: any) {
const result = await this.lambdaService.invoke<ValidationResult>({
functionName: 'validator-service',
body: {
data,
rules
}
});
if (!result.isValid) {
throw new Error(`Validation failed: ${result.errors.join(', ')}`);
}
return result;
}
// Chain multiple Lambda functions
async processOrder(order: any) {
// Step 1: Validate order
await this.validateData(order, {
required: ['customerId', 'items', 'paymentMethod']
});
// Step 2: Calculate totals
const calculation = await this.calculate('sum',
order.items.map(item => item.price * item.quantity)
);
// Step 3: Process payment
const payment = await this.lambdaService.invoke<{transactionId: string}>({
functionName: 'payment-processor',
body: {
amount: calculation.result,
paymentMethod: order.paymentMethod,
customerId: order.customerId
}
});
return {
orderId: order.id,
total: calculation.result,
transactionId: payment.transactionId
};
}
}Error Handling
try {
const result = await lambdaService.invoke({
functionName: 'my-function',
body: { data: 'test' }
});
} catch (error) {
if (error.name === 'ResourceNotFoundException') {
console.error('Lambda function not found');
} else if (error.name === 'TooManyRequestsException') {
console.error('Rate limit exceeded');
} else if (error.FunctionError) {
console.error('Lambda function error:', error.Payload);
}
}Environment Variables
# Required: AWS region
AWS_REGION=us-east-1
# Optional: AWS profile
AWS_PROFILE=my-profileAWS Credentials
The module uses the standard AWS SDK credential chain:
- Environment variables
- Shared credentials file
- IAM roles (for EC2/ECS/Lambda)
Limitations
- Only supports synchronous invocation (RequestResponse)
- No built-in retry logic
- Assumes JSON payloads and responses
- For advanced invocation options, use the exposed
lambdaClientdirectly
Best Practices
- Function Naming: Use consistent naming conventions for Lambda functions
- Error Handling: Always handle potential Lambda errors and timeouts
- Payload Size: Keep payloads under 6 MB (synchronous invocation limit)
- Timeouts: Set appropriate timeouts for your Lambda functions
- Monitoring: Use CloudWatch Logs and X-Ray for debugging
License
MIT
