# AWS SDK for JavaScript v3 The AWS SDK for JavaScript v3 is a modular rewrite of v2 with separate packages for each AWS service. It provides a first-class TypeScript experience, a powerful middleware stack for request/response customization, and improved performance through modular architecture. The SDK supports Node.js, browser, and React Native environments, enabling developers to build applications that interact with over 400 AWS services. The SDK follows a command pattern where each service operation is represented as a separate Command class. Clients are initialized with configuration options (credentials, region, etc.) and commands are executed via the `.send()` method. This modular design allows tree-shaking to reduce bundle sizes, making it particularly efficient for serverless applications where cold start time is critical. --- ## Service Client Initialization Create and configure AWS service clients with region, credentials, and custom HTTP options. All clients follow the same pattern: instantiate with configuration, then call `.send()` with command objects. ```javascript import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; import { S3Client } from "@aws-sdk/client-s3"; // Basic client with region const dynamoClient = new DynamoDBClient({ region: "us-west-2" }); // Client with explicit credentials const s3Client = new S3Client({ region: "us-east-1", credentials: { accessKeyId: "AKIAIOSFODNN7EXAMPLE", secretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", }, }); // Client with custom HTTP options (Node.js) const clientWithTimeout = new DynamoDBClient({ region: "us-west-2", requestHandler: { connectionTimeout: 5000, requestTimeout: 10000, httpsAgent: { maxSockets: 100 }, }, }); // Using the client import { ListTablesCommand } from "@aws-sdk/client-dynamodb"; const result = await dynamoClient.send(new ListTablesCommand({})); console.log("Tables:", result.TableNames); // Output: Tables: ["users", "orders", "products"] ``` --- ## S3 Operations - GetObject and PutObject Perform common S3 operations including uploading files, downloading objects, and handling streaming responses. The SDK provides helper methods on stream responses for easy conversion. ```javascript import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"; import { readFile } from "fs/promises"; const s3 = new S3Client({ region: "us-west-2" }); // Upload a file const uploadResult = await s3.send(new PutObjectCommand({ Bucket: "my-bucket", Key: "documents/report.pdf", Body: await readFile("./report.pdf"), ContentType: "application/pdf", Metadata: { "uploaded-by": "user-123", "department": "finance", }, })); console.log("Upload ETag:", uploadResult.ETag); // Output: Upload ETag: "d41d8cd98f00b204e9800998ecf8427e" // Download and read object const getResult = await s3.send(new GetObjectCommand({ Bucket: "my-bucket", Key: "documents/config.json", })); // Convert stream to string using SDK helper const bodyString = await getResult.Body.transformToString(); const config = JSON.parse(bodyString); console.log("Config:", config); // Output: Config: { "setting": "value", "enabled": true } // Handle errors with metadata try { await s3.send(new GetObjectCommand({ Bucket: "my-bucket", Key: "nonexistent.txt", })); } catch (error) { if (error.name === "NoSuchKey") { console.log("Object not found"); console.log("Request ID:", error.$metadata.requestId); } } ``` --- ## S3 Multipart Upload with lib-storage Upload large files efficiently using automatic multipart uploads with configurable concurrency. The Upload class handles chunking, parallel uploads, and progress tracking. ```javascript import { Upload } from "@aws-sdk/lib-storage"; import { S3Client } from "@aws-sdk/client-s3"; import { createReadStream } from "fs"; const s3Client = new S3Client({ region: "us-west-2" }); // Upload large file with progress tracking const upload = new Upload({ client: s3Client, params: { Bucket: "my-bucket", Key: "videos/large-video.mp4", Body: createReadStream("./large-video.mp4"), ContentType: "video/mp4", }, queueSize: 4, // Concurrent part uploads partSize: 1024 * 1024 * 10, // 10MB parts (minimum 5MB) leavePartsOnError: false, }); // Track upload progress upload.on("httpUploadProgress", (progress) => { const percent = Math.round((progress.loaded / progress.total) * 100); console.log(`Upload progress: ${percent}% (${progress.loaded}/${progress.total} bytes)`); }); // Output: Upload progress: 25% (26214400/104857600 bytes) // Output: Upload progress: 50% (52428800/104857600 bytes) // ... const result = await upload.done(); console.log("Upload complete:", result.Location); // Output: Upload complete: https://my-bucket.s3.us-west-2.amazonaws.com/videos/large-video.mp4 ``` --- ## S3 Presigned URLs Generate time-limited presigned URLs for secure object access without exposing credentials. Useful for temporary download links or allowing uploads directly to S3. ```javascript import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"; const s3Client = new S3Client({ region: "us-west-2" }); // Generate presigned URL for download (1 hour expiry) const downloadCommand = new GetObjectCommand({ Bucket: "my-bucket", Key: "private/document.pdf", }); const downloadUrl = await getSignedUrl(s3Client, downloadCommand, { expiresIn: 3600 }); console.log("Download URL:", downloadUrl); // Output: Download URL: https://my-bucket.s3.us-west-2.amazonaws.com/private/document.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Expires=3600&X-Amz-Signature=... // Generate presigned URL for upload with content-type requirement const uploadCommand = new PutObjectCommand({ Bucket: "my-bucket", Key: "uploads/user-photo.jpg", ContentType: "image/jpeg", }); const uploadUrl = await getSignedUrl(s3Client, uploadCommand, { expiresIn: 900, signableHeaders: new Set(["content-type"]), }); // Client can upload with curl: // curl -X PUT -H "Content-Type: image/jpeg" --data-binary @photo.jpg "uploadUrl" // Presigned URL with server-side encryption headers const sseCommand = new PutObjectCommand({ Bucket: "my-bucket", Key: "encrypted/secret.txt", ServerSideEncryption: "aws:kms", SSEKMSKeyId: "arn:aws:kms:us-west-2:123456789012:key/abcd-1234", }); const sseUrl = await getSignedUrl(s3Client, sseCommand, { expiresIn: 900, hoistableHeaders: new Set(["x-amz-server-side-encryption", "x-amz-server-side-encryption-aws-kms-key-id"]), }); ``` --- ## DynamoDB Document Client Simplify DynamoDB operations by automatically marshalling/unmarshalling native JavaScript types to DynamoDB attribute values. Eliminates the need to manually specify type descriptors. ```javascript import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; import { DynamoDBDocumentClient, PutCommand, GetCommand, QueryCommand } from "@aws-sdk/lib-dynamodb"; const client = new DynamoDBClient({ region: "us-west-2" }); const docClient = DynamoDBDocumentClient.from(client, { marshallOptions: { removeUndefinedValues: true, convertClassInstanceToMap: true, }, unmarshallOptions: { wrapNumbers: false, }, }); // Put item with native JavaScript types await docClient.send(new PutCommand({ TableName: "Users", Item: { userId: "user-123", email: "alice@example.com", age: 30, active: true, tags: ["premium", "verified"], preferences: { theme: "dark", notifications: true, }, createdAt: new Date().toISOString(), }, })); // Get item const { Item } = await docClient.send(new GetCommand({ TableName: "Users", Key: { userId: "user-123" }, })); console.log("User:", Item); // Output: User: { userId: "user-123", email: "alice@example.com", age: 30, active: true, ... } // Query with filter expression const { Items } = await docClient.send(new QueryCommand({ TableName: "Users", KeyConditionExpression: "userId = :uid", FilterExpression: "age >= :minAge AND active = :isActive", ExpressionAttributeValues: { ":uid": "user-123", ":minAge": 18, ":isActive": true, }, })); console.log("Found users:", Items.length); ``` --- ## DynamoDB Pagination with Paginators Iterate through large result sets efficiently using built-in async generators. Paginators automatically handle continuation tokens and provide a clean async iteration interface. ```javascript import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; import { DynamoDBDocumentClient, paginateScan, paginateQuery } from "@aws-sdk/lib-dynamodb"; const client = new DynamoDBClient({ region: "us-west-2" }); const docClient = DynamoDBDocumentClient.from(client); // Scan entire table with pagination const allItems = []; for await (const page of paginateScan({ client: docClient }, { TableName: "Products", Limit: 100, // Items per page })) { allItems.push(...page.Items); console.log(`Fetched ${page.Items.length} items, total: ${allItems.length}`); } // Output: Fetched 100 items, total: 100 // Output: Fetched 100 items, total: 200 // Output: Fetched 47 items, total: 247 // Query with pagination const orderItems = []; for await (const page of paginateQuery({ client: docClient, pageSize: 25 }, { TableName: "Orders", KeyConditionExpression: "customerId = :cid", ExpressionAttributeValues: { ":cid": "customer-456" }, })) { for (const order of page.Items) { orderItems.push(order); // Process each order console.log(`Order: ${order.orderId}, Total: $${order.total}`); } } // Output: Order: order-001, Total: $150.00 // Output: Order: order-002, Total: $75.50 ``` --- ## DynamoDB Large Numbers with NumberValue Handle numbers larger than JavaScript's Number.MAX_SAFE_INTEGER using the NumberValue class for precise round-trip storage of arbitrary-precision numbers. ```javascript import { DynamoDB } from "@aws-sdk/client-dynamodb"; import { DynamoDBDocument, NumberValue } from "@aws-sdk/lib-dynamodb"; const client = DynamoDBDocument.from(new DynamoDB({ region: "us-west-2" }), { marshallOptions: { // Throw error for imprecise numbers (recommended) allowImpreciseNumbers: false, }, unmarshallOptions: { // Return NumberValue for all numbers wrapNumbers: true, }, }); // Store precise large numbers await client.put({ TableName: "Transactions", Item: { txId: "tx-001", // Use NumberValue for precise large numbers amount: NumberValue.from("12345678901234567890.123456789"), timestamp: Date.now(), }, }); // Read and handle large numbers const result = await client.get({ TableName: "Transactions", Key: { txId: "tx-001" }, }); const amount = result.Item.amount; // amount is a NumberValue instance console.log("Amount string:", amount.toString()); // Output: Amount string: 12345678901234567890.123456789 // Custom number handler with BigInt const bigIntClient = DynamoDBDocument.from(new DynamoDB({}), { unmarshallOptions: { wrapNumbers: (str) => { if (str.includes(".")) return parseFloat(str); return BigInt(str); }, }, }); ``` --- ## Credential Providers Configure credential providers for various authentication scenarios including environment variables, shared credentials files, IAM roles, and SSO. ```javascript import { S3Client } from "@aws-sdk/client-s3"; import { fromEnv, fromIni, fromNodeProviderChain, fromTemporaryCredentials, fromCognitoIdentityPool, } from "@aws-sdk/credential-providers"; // From environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) const envClient = new S3Client({ region: "us-west-2", credentials: fromEnv(), }); // From shared credentials file (~/.aws/credentials) const profileClient = new S3Client({ region: "us-west-2", credentials: fromIni({ profile: "production", filepath: "~/.aws/credentials", configFilepath: "~/.aws/config", }), }); // Default provider chain (env -> shared file -> EC2/ECS metadata) const defaultClient = new S3Client({ region: "us-west-2", credentials: fromNodeProviderChain({ clientConfig: { region: "us-west-2" }, }), }); // Assume IAM role with temporary credentials const roleClient = new S3Client({ region: "us-west-2", credentials: fromTemporaryCredentials({ params: { RoleArn: "arn:aws:iam::123456789012:role/S3ReadOnlyRole", RoleSessionName: "my-session", DurationSeconds: 3600, }, // Optional: MFA support mfaCodeProvider: async (serialNumber) => { return "123456"; // Return MFA code }, }), }); // Cognito Identity Pool for browser/mobile apps const cognitoClient = new S3Client({ region: "us-west-2", credentials: fromCognitoIdentityPool({ identityPoolId: "us-west-2:12345678-1234-1234-1234-123456789012", clientConfig: { region: "us-west-2" }, }), }); ``` --- ## Middleware Stack Customization Add custom middleware to intercept and modify requests/responses at various stages of the operation lifecycle. Middleware can log, transform, add headers, or implement cross-cutting concerns. ```javascript import { DynamoDBClient, ListTablesCommand } from "@aws-sdk/client-dynamodb"; const client = new DynamoDBClient({ region: "us-west-2" }); // Add logging middleware client.middlewareStack.add( (next, context) => async (args) => { console.log(`[${context.clientName}] ${context.commandName}`); console.log("Request input:", JSON.stringify(args.input, null, 2)); const start = Date.now(); const result = await next(args); const duration = Date.now() - start; console.log(`Response received in ${duration}ms`); console.log("Output:", JSON.stringify(result.output, null, 2)); return result; }, { step: "initialize", name: "LoggingMiddleware", tags: ["LOGGING"], override: true, } ); // Add custom headers middleware client.middlewareStack.add( (next) => async (args) => { args.request.headers["x-custom-trace-id"] = `trace-${Date.now()}`; args.request.headers["x-client-version"] = "1.0.0"; return next(args); }, { step: "build", name: "CustomHeadersMiddleware", priority: "high", override: true, } ); // Execute with middleware const result = await client.send(new ListTablesCommand({})); // Console output: // [DynamoDBClient] ListTablesCommand // Request input: {} // Response received in 145ms // Output: { "TableNames": ["Users", "Orders"] } ``` --- ## Error Handling and Retries Handle service errors with detailed metadata and configure retry behavior for transient failures. The SDK provides structured error information including request IDs for debugging. ```javascript import { S3Client, GetObjectCommand, S3ServiceException } from "@aws-sdk/client-s3"; import { DynamoDBClient, GetItemCommand } from "@aws-sdk/client-dynamodb"; // Configure client with retry options const s3Client = new S3Client({ region: "us-west-2", maxAttempts: 5, // Total attempts (retries + 1) }); // Handle S3 errors async function getS3Object(bucket, key) { try { const response = await s3Client.send(new GetObjectCommand({ Bucket: bucket, Key: key, })); return await response.Body.transformToString(); } catch (error) { // Access error metadata const { requestId, cfId, extendedRequestId, httpStatusCode } = error.$metadata; console.log("Error details:", { name: error.name, message: error.message, requestId, statusCode: httpStatusCode, }); // Handle specific error types if (error.name === "NoSuchKey") { console.log(`Object ${key} not found in bucket ${bucket}`); return null; } else if (error.name === "NoSuchBucket") { throw new Error(`Bucket ${bucket} does not exist`); } else if (error.name === "AccessDenied") { throw new Error(`Access denied to ${bucket}/${key}`); } throw error; } } // DynamoDB conditional check failure const dynamoClient = new DynamoDBClient({ region: "us-west-2" }); try { await dynamoClient.send(new GetItemCommand({ TableName: "Users", Key: { userId: { S: "nonexistent" } }, })); } catch (error) { if (error.name === "ResourceNotFoundException") { console.log("Table does not exist"); } else if (error.name === "ProvisionedThroughputExceededException") { console.log("Rate limited, backing off..."); } } ``` --- ## Abort Controller for Request Cancellation Cancel in-flight requests using the AbortController interface. Useful for implementing timeouts, user-initiated cancellations, or cleaning up resources. ```javascript import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"; const s3Client = new S3Client({ region: "us-west-2" }); // Cancel request after timeout async function getWithTimeout(bucket, key, timeoutMs) { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeoutMs); try { const response = await s3Client.send( new GetObjectCommand({ Bucket: bucket, Key: key }), { abortSignal: controller.signal } ); clearTimeout(timeoutId); return response; } catch (error) { clearTimeout(timeoutId); if (error.name === "AbortError") { console.log(`Request timed out after ${timeoutMs}ms`); return null; } throw error; } } // User-initiated cancellation (e.g., React component) class UploadManager { constructor() { this.controller = null; } async startUpload(file) { this.controller = new AbortController(); try { await s3Client.send( new PutObjectCommand({ Bucket: "my-bucket", Key: `uploads/${file.name}`, Body: file, }), { abortSignal: this.controller.signal } ); console.log("Upload complete"); } catch (error) { if (error.name === "AbortError") { console.log("Upload cancelled by user"); } else { throw error; } } } cancelUpload() { if (this.controller) { this.controller.abort(); console.log("Cancellation requested"); } } } const manager = new UploadManager(); // manager.cancelUpload(); // Call to cancel ``` --- ## Lambda Best Practices Optimize SDK usage in AWS Lambda with proper client initialization, credential handling, and connection reuse for reduced cold start times and improved performance. ```javascript import { DynamoDBClient, GetItemCommand, PutItemCommand } from "@aws-sdk/client-dynamodb"; import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"; // Initialize clients OUTSIDE handler for connection reuse const dynamoClient = new DynamoDBClient({}); // Uses Lambda execution role const s3Client = new S3Client({}); // Handler function export const handler = async (event) => { const response = { statusCode: 200, headers: { "Content-Type": "application/json" }, }; try { // Parse incoming event const { userId, action } = event.body ? JSON.parse(event.body) : event; if (action === "get") { // Get user from DynamoDB const result = await dynamoClient.send(new GetItemCommand({ TableName: process.env.USERS_TABLE, Key: { userId: { S: userId } }, })); response.body = JSON.stringify({ user: result.Item ? { userId: result.Item.userId.S, email: result.Item.email.S, } : null, }); } else if (action === "getConfig") { // Get config from S3 const s3Result = await s3Client.send(new GetObjectCommand({ Bucket: process.env.CONFIG_BUCKET, Key: "config.json", })); const configStr = await s3Result.Body.transformToString(); response.body = configStr; } } catch (error) { console.error("Error:", error); response.statusCode = 500; response.body = JSON.stringify({ message: "Internal server error", requestId: error.$metadata?.requestId, }); } return response; }; // For bundled deployments (recommended for cold start optimization): // Use esbuild or webpack to bundle your Lambda function // This reduces module resolution time significantly ``` --- ## STS AssumeRole and Cross-Account Access Use AWS Security Token Service (STS) to assume IAM roles for cross-account access or temporary elevated permissions. ```javascript import { STSClient, AssumeRoleCommand, GetCallerIdentityCommand } from "@aws-sdk/client-sts"; import { S3Client, ListBucketsCommand } from "@aws-sdk/client-s3"; import { fromTemporaryCredentials } from "@aws-sdk/credential-providers"; const stsClient = new STSClient({ region: "us-east-1" }); // Get current identity const identity = await stsClient.send(new GetCallerIdentityCommand({})); console.log("Current account:", identity.Account); console.log("Current ARN:", identity.Arn); // Output: Current account: 123456789012 // Output: Current ARN: arn:aws:iam::123456789012:user/developer // Assume role manually const assumeRoleResponse = await stsClient.send(new AssumeRoleCommand({ RoleArn: "arn:aws:iam::987654321098:role/CrossAccountS3Access", RoleSessionName: "cross-account-session", DurationSeconds: 3600, ExternalId: "shared-secret-123", // If required by trust policy })); // Create client with assumed role credentials const crossAccountS3 = new S3Client({ region: "us-west-2", credentials: { accessKeyId: assumeRoleResponse.Credentials.AccessKeyId, secretAccessKey: assumeRoleResponse.Credentials.SecretAccessKey, sessionToken: assumeRoleResponse.Credentials.SessionToken, expiration: assumeRoleResponse.Credentials.Expiration, }, }); const buckets = await crossAccountS3.send(new ListBucketsCommand({})); console.log("Cross-account buckets:", buckets.Buckets.map(b => b.Name)); // Using credential provider (auto-refreshes) const autoRefreshS3 = new S3Client({ region: "us-west-2", credentials: fromTemporaryCredentials({ params: { RoleArn: "arn:aws:iam::987654321098:role/CrossAccountS3Access", RoleSessionName: "auto-refresh-session", }, }), }); ``` --- ## CloudWatch Logs and Metrics Send custom metrics and query logs using CloudWatch clients for application monitoring and observability. ```javascript import { CloudWatchClient, PutMetricDataCommand, GetMetricStatisticsCommand } from "@aws-sdk/client-cloudwatch"; import { CloudWatchLogsClient, PutLogEventsCommand, StartQueryCommand, GetQueryResultsCommand, } from "@aws-sdk/client-cloudwatch-logs"; const cwClient = new CloudWatchClient({ region: "us-west-2" }); const logsClient = new CloudWatchLogsClient({ region: "us-west-2" }); // Publish custom metrics await cwClient.send(new PutMetricDataCommand({ Namespace: "MyApplication", MetricData: [ { MetricName: "ProcessedOrders", Value: 150, Unit: "Count", Dimensions: [ { Name: "Environment", Value: "production" }, { Name: "Region", Value: "us-west-2" }, ], }, { MetricName: "OrderProcessingTime", Value: 1250, Unit: "Milliseconds", Dimensions: [ { Name: "Environment", Value: "production" }, ], }, ], })); console.log("Metrics published successfully"); // Query metrics const stats = await cwClient.send(new GetMetricStatisticsCommand({ Namespace: "MyApplication", MetricName: "ProcessedOrders", StartTime: new Date(Date.now() - 3600000), // Last hour EndTime: new Date(), Period: 300, // 5 minutes Statistics: ["Sum", "Average"], Dimensions: [{ Name: "Environment", Value: "production" }], })); console.log("Metric stats:", stats.Datapoints); // Query CloudWatch Logs Insights const query = await logsClient.send(new StartQueryCommand({ logGroupName: "/aws/lambda/my-function", startTime: Math.floor((Date.now() - 3600000) / 1000), endTime: Math.floor(Date.now() / 1000), queryString: ` fields @timestamp, @message | filter @message like /ERROR/ | sort @timestamp desc | limit 20 `, })); // Wait and get results await new Promise(resolve => setTimeout(resolve, 2000)); const results = await logsClient.send(new GetQueryResultsCommand({ queryId: query.queryId, })); console.log("Log query results:", results.results); ``` --- ## Lambda Function Invocation Invoke Lambda functions synchronously or asynchronously, handle responses, and manage payload encoding. ```javascript import { LambdaClient, InvokeCommand, InvokeAsyncCommand } from "@aws-sdk/client-lambda"; const lambdaClient = new LambdaClient({ region: "us-west-2" }); // Synchronous invocation (RequestResponse) const syncResponse = await lambdaClient.send(new InvokeCommand({ FunctionName: "process-order", InvocationType: "RequestResponse", Payload: JSON.stringify({ orderId: "order-12345", customerId: "customer-789", items: [ { productId: "prod-001", quantity: 2 }, { productId: "prod-002", quantity: 1 }, ], }), })); // Parse response payload const responsePayload = JSON.parse(new TextDecoder().decode(syncResponse.Payload)); console.log("Lambda response:", responsePayload); console.log("Status code:", syncResponse.StatusCode); // Output: Lambda response: { "success": true, "orderId": "order-12345", "total": 150.00 } // Output: Status code: 200 // Check for function errors if (syncResponse.FunctionError) { console.error("Function error:", syncResponse.FunctionError); console.error("Error details:", responsePayload); } // Asynchronous invocation (Event) const asyncResponse = await lambdaClient.send(new InvokeCommand({ FunctionName: "send-notification", InvocationType: "Event", // Fire and forget Payload: JSON.stringify({ userId: "user-123", message: "Your order has been shipped!", channels: ["email", "push"], }), })); console.log("Async invocation accepted:", asyncResponse.StatusCode === 202); // Output: Async invocation accepted: true // Invoke with client context const contextResponse = await lambdaClient.send(new InvokeCommand({ FunctionName: "my-function", InvocationType: "RequestResponse", ClientContext: Buffer.from(JSON.stringify({ custom: { traceId: "trace-abc-123" }, env: { platform: "web" }, })).toString("base64"), Payload: JSON.stringify({ action: "test" }), })); ``` --- ## Secrets Manager Securely retrieve and manage secrets for database credentials, API keys, and other sensitive configuration data. ```javascript import { SecretsManagerClient, GetSecretValueCommand, CreateSecretCommand, UpdateSecretCommand, RotateSecretCommand, } from "@aws-sdk/client-secrets-manager"; const secretsClient = new SecretsManagerClient({ region: "us-west-2" }); // Retrieve secret value async function getSecret(secretName) { const response = await secretsClient.send(new GetSecretValueCommand({ SecretId: secretName, })); // Secrets can be string or binary if (response.SecretString) { return JSON.parse(response.SecretString); } // Handle binary secrets return Buffer.from(response.SecretBinary).toString("utf-8"); } // Get database credentials const dbCreds = await getSecret("production/db/postgres"); console.log("Database config:", { host: dbCreds.host, port: dbCreds.port, username: dbCreds.username, // password is also available but don't log it! }); // Output: Database config: { host: "db.example.com", port: 5432, username: "app_user" } // Create new secret await secretsClient.send(new CreateSecretCommand({ Name: "production/api/stripe", Description: "Stripe API keys for production", SecretString: JSON.stringify({ publishableKey: "pk_live_xxx", secretKey: "sk_live_xxx", }), Tags: [ { Key: "Environment", Value: "production" }, { Key: "Service", Value: "payments" }, ], })); // Update existing secret await secretsClient.send(new UpdateSecretCommand({ SecretId: "production/api/stripe", SecretString: JSON.stringify({ publishableKey: "pk_live_new", secretKey: "sk_live_new", }), })); // Trigger secret rotation await secretsClient.send(new RotateSecretCommand({ SecretId: "production/db/postgres", RotationLambdaARN: "arn:aws:lambda:us-west-2:123456789012:function:rotate-db-secret", })); ``` --- ## SNS and SQS Messaging Publish messages to SNS topics and interact with SQS queues for event-driven architectures and message processing. ```javascript import { SNSClient, PublishCommand, PublishBatchCommand } from "@aws-sdk/client-sns"; import { SQSClient, SendMessageCommand, ReceiveMessageCommand, DeleteMessageCommand, } from "@aws-sdk/client-sqs"; const snsClient = new SNSClient({ region: "us-west-2" }); const sqsClient = new SQSClient({ region: "us-west-2" }); // Publish to SNS topic const snsResponse = await snsClient.send(new PublishCommand({ TopicArn: "arn:aws:sns:us-west-2:123456789012:order-notifications", Subject: "New Order Received", Message: JSON.stringify({ orderId: "order-12345", customerEmail: "customer@example.com", total: 99.99, }), MessageAttributes: { orderType: { DataType: "String", StringValue: "standard", }, priority: { DataType: "Number", StringValue: "1", }, }, })); console.log("SNS MessageId:", snsResponse.MessageId); // Batch publish to SNS await snsClient.send(new PublishBatchCommand({ TopicArn: "arn:aws:sns:us-west-2:123456789012:notifications", PublishBatchRequestEntries: [ { Id: "msg1", Message: JSON.stringify({ type: "alert", text: "Alert 1" }) }, { Id: "msg2", Message: JSON.stringify({ type: "info", text: "Info 1" }) }, ], })); // Send message to SQS queue await sqsClient.send(new SendMessageCommand({ QueueUrl: "https://sqs.us-west-2.amazonaws.com/123456789012/order-processing", MessageBody: JSON.stringify({ orderId: "order-67890", action: "process", }), DelaySeconds: 10, MessageAttributes: { Priority: { DataType: "Number", StringValue: "5", }, }, })); // Receive and process SQS messages const messages = await sqsClient.send(new ReceiveMessageCommand({ QueueUrl: "https://sqs.us-west-2.amazonaws.com/123456789012/order-processing", MaxNumberOfMessages: 10, WaitTimeSeconds: 20, // Long polling MessageAttributeNames: ["All"], })); for (const message of messages.Messages || []) { const body = JSON.parse(message.Body); console.log("Processing:", body.orderId); // Delete message after processing await sqsClient.send(new DeleteMessageCommand({ QueueUrl: "https://sqs.us-west-2.amazonaws.com/123456789012/order-processing", ReceiptHandle: message.ReceiptHandle, })); } ``` --- The AWS SDK for JavaScript v3 is designed for building scalable cloud applications across Node.js, browser, and serverless environments. Its modular architecture enables importing only the needed service clients and commands, resulting in smaller bundles and faster load times. The middleware stack provides extensibility for logging, metrics, custom headers, and request transformation at any stage of the operation lifecycle. Common integration patterns include: Lambda functions with DynamoDB for serverless APIs, S3 for file storage with presigned URLs for secure client uploads, SQS/SNS for decoupled microservices communication, and Secrets Manager for secure credential storage. The SDK's credential provider chain automatically handles authentication across development environments (env vars, credential files) and production (IAM roles, EC2 metadata), making it seamless to deploy the same code across different environments without configuration changes.