Introduction
AWS Bedrock provides access to foundation models like Claude 3 or Llama 3 without managing infrastructure. This tutorial shows how to integrate it into a Node.js application for text generation and streaming responses. You'll learn best practices for configuration, authentication, and error handling for production deployments.
Prerequisites
- Node.js 20+
- AWS account with Bedrock access
- Basic TypeScript knowledge
- AWS CLI configured
Installing Dependencies
npm init -y
npm install @aws-sdk/client-bedrock-runtime dotenvInstalls the official AWS SDK for Bedrock and dotenv for securely managing environment variables.
Bedrock Client Configuration
import { BedrockRuntimeClient } from '@aws-sdk/client-bedrock-runtime';
import * as dotenv from 'dotenv';
dotenv.config();
export const bedrockClient = new BedrockRuntimeClient({
region: process.env.AWS_REGION || 'us-east-1',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
});Initializes the Bedrock client with AWS credentials. Use environment variables to avoid hardcoding keys.
Simple Model Invocation
import { InvokeModelCommand } from '@aws-sdk/client-bedrock-runtime';
import { bedrockClient } from './bedrockClient';
export async function invokeClaude(prompt: string) {
const command = new InvokeModelCommand({
modelId: 'anthropic.claude-3-sonnet-20240229-v1:0',
contentType: 'application/json',
accept: 'application/json',
body: JSON.stringify({
anthropic_version: 'bedrock-2023-05-31',
max_tokens: 1000,
messages: [{ role: 'user', content: prompt }],
}),
});
const response = await bedrockClient.send(command);
return JSON.parse(new TextDecoder().decode(response.body));
}Sends a request to Claude 3 Sonnet. The request body must follow Anthropic's specific format.
Streaming Response Handling
import { InvokeModelWithResponseStreamCommand } from '@aws-sdk/client-bedrock-runtime';
import { bedrockClient } from './bedrockClient';
export async function streamClaude(prompt: string) {
const command = new InvokeModelWithResponseStreamCommand({
modelId: 'anthropic.claude-3-sonnet-20240229-v1:0',
contentType: 'application/json',
body: JSON.stringify({
anthropic_version: 'bedrock-2023-05-31',
max_tokens: 1000,
messages: [{ role: 'user', content: prompt }],
}),
});
const response = await bedrockClient.send(command);
for await (const event of response.body!) {
if (event.chunk) {
const chunk = JSON.parse(new TextDecoder().decode(event.chunk.bytes));
if (chunk.delta?.text) process.stdout.write(chunk.delta.text);
}
}
}Uses streaming to display tokens as they arrive, improving the user experience.
Error Handling
import { BedrockRuntimeServiceException } from '@aws-sdk/client-bedrock-runtime';
export function handleBedrockError(error: unknown) {
if (error instanceof BedrockRuntimeServiceException) {
console.error(`Bedrock error: ${error.name} - ${error.message}`);
if (error.name === 'ValidationException') {
throw new Error('Invalid prompt or incorrect parameters');
}
}
throw error;
}Catches Bedrock-specific exceptions to provide clear, actionable error messages.
Best Practices
- Always validate and sanitize prompts before sending
- Use models via aliases to simplify updates
- Implement retry with exponential backoff
- Monitor costs with CloudWatch
- Store credentials via IAM roles instead of static keys
Common Mistakes to Avoid
- Forgetting to request model access in the Bedrock console
- Using an incorrect body format for the chosen model
- Not handling token limits and timeouts
- Ignoring regional differences for certain models
Further Reading
Explore our advanced generative AI and AWS courses: https://learni-group.com/formations